Working on porting to 3.10

gr-droneid-update-3.10
David Protzman 2022-09-22 21:03:39 -04:00
rodzic 3bc45fe703
commit ce69f6fc3c
108 zmienionych plików z 4328 dodań i 7218 usunięć

Wyświetl plik

@ -0,0 +1,104 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlinesLeft: true
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: false
BinPackParameters: false
BreakBeforeBraces: Custom
BraceWrapping:
AfterClass: true
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 90
CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeCategories:
- Regex: '^"(gnuradio)/'
Priority: 1
- Regex: '^<(gnuradio)/'
Priority: 2
- Regex: '^<(boost)/'
Priority: 98
- Regex: '^<[a-z]*>$'
Priority: 99
- Regex: '^".*"$'
Priority: 0
- Regex: '.*'
Priority: 10
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 2
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never

Wyświetl plik

@ -0,0 +1,110 @@
# gr-droneid conda recipe
This recipe is for creating a package that can be installed into a [conda](https://docs.conda.io/en/latest/) environment. See the [Conda GNU Radio Guide](https://wiki.gnuradio.org/index.php/CondaInstall) for more information on using GNU Radio with conda.
Packages for GNU Radio and some out-of-tree (OOT) modules are available through the [`conda-forge` channel](https://conda-forge.org/). If this OOT module is already available (search "gnuradio" on [anaconda.org](https://anaconda.org)), it is preferable to use that existing package rather than this recipe.
#### Users
- [Building the package](#building-the-package)
#### Developers
- [Modifying the recipe](#modifying-the-recipe)
- [Continuous integration](#continuous-integration)
## Building the package
(See the [Conda GNU Radio Guide](https://wiki.gnuradio.org/index.php/CondaInstall) if you are unfamiliar with how to use conda.)
1. Make sure that have `conda-build` and `conda-forge-pinning` installed and updated in your base environment:
conda activate base
conda install -n base conda-build conda-forge-pinning
conda upgrade -n base conda-build conda-forge-pinning
**Windows users only**: you will also need to have Microsoft's Visual C++ build tools installed. Usually you can do this by installing the [Community edition of Visual Studio](https://visualstudio.microsoft.com/free-developer-offers/) and then selecting a MSVC C++ x64/x86 build tools component under the list of "Individual Components". As of this writing, you will specifically need MSVC v141, i.e. the "MSVC v141 - VS2017 C++ x64/x86 build tools (v14.16)" component. If the build fails to find the version of MSVC it is looking for, try installing other (newer) versions.
2. Download the source code for this OOT module (which includes this recipe). Typically, this is done by using `git` and cloning the module's repository:
git clone <repository_url>
cd <repository_name>
3. Run `conda-build` on the recipe to create the package:
(Linux and macOS)
conda build .conda/recipe/ -m ${CONDA_PREFIX}/conda_build_config.yaml
(Windows)
conda build .conda\recipe\ -m %CONDA_PREFIX%\conda_build_config.yaml
If you plan on using this package within an existing environment which uses a specific version of Python, specify the version of Python using the `--python` flag. You must use a version string that matches one of the strings listed under `python` in the `${CONDA_PREFIX}/conda_build_config.yaml` file, e.g:
(Linux and macOS)
conda build .conda/recipe/ -m ${CONDA_PREFIX}/conda_build_config.yaml --python="3.9.* *_cpython"
(Windows)
conda build .conda\recipe\ -m %CONDA_PREFIX%\conda_build_config.yaml --python="3.9.* *_cpython"
If you encounter errors, consult with the OOT module maintainer or the maintainers of the [gnuradio feedstock](https://github.com/conda-forge/gnuradio-feedstock). It is possible that the recipe will need to be updated.
4. Install the package into an existing environment
conda install --use-local -n <environment_name> gnuradio-EXAMPLE
or create a new environment that includes the package:
conda create -n test_env gnuradio-EXAMPLE
## Modifying the recipe
This recipe is derived from a template, and so it is best to check it and make any necessary modifications. Likely changes include:
- Populating metadata near the bottom of the `recipe/meta.yaml` file
- Adding "host" (build-time) and "run" (run-time) dependencies specific to your module in `recipe/meta.yaml`
- Adding special configuration flags or steps are necessary to carry out the build to the build scripts (`recipe/build.sh` for Linux/macOS and `recipe/bld.bat` for Windows)
Specifying the versions of GNU Radio that your OOT is compatible with is one of the most important modifications. Following the instructions below, the module will be built against the conda-forge "pinned" version of GNU Radio, which is usually the latest version.
- To override the pinned version of GNU Radio (e.g. for a branch that builds against an older version), specify the `gnuradio_core` key as instructed in `recipe/conda_build_config.yaml`.
- If the module is compatible with multiple major versions of GNU Radio, and you want to build against multiple of them, you can also add extra versions to `recipe/conda_build_config.yaml` to expand the default build matrix.
See the [conda-build documentation](https://docs.conda.io/projects/conda-build/en/latest/index.html) for details on how to write a conda recipe.
## Continuous integration
Only a few steps are needed to use this recipe to build and test this OOT module using CI services. It can also be used to upload packages to [anaconda.org](https://anaconda.org) for others to download and use.
1. Make sure that have `conda-smithy` installed in your base conda environment:
conda activate base
conda install -n base conda-smithy
conda upgrade -n base conda-smithy
2. Make any changes to the recipe and `conda-forge.yml` that are necessary. For example, if you plan on uploading packages to your own [anaconda.org](https://anaconda.org) channel, specify the channel name and label as the `channel_targets` key in `recipe/conda_build_config.yaml`. Commit the changes to your repository:
git commit -a
3. "Re-render" the CI scripts by running conda-smithy from the root of your repository:
conda-smithy rerender --feedstock_config .conda/conda-forge.yml -c auto
This will create a commit that adds or updates the CI scripts that have been configured with `conda-forge.yml`. If you want to minimize extraneous files, you can remove some of the newly-created files that are not necessary outside of a typical conda-forge feedstock:
git rm -f .github/workflows/automerge.yml .github/workflows/webservices.yml .circleci/config.yml
git commit --amend -s
When the CI is executed (on a pull request or commit), it will run one job per configuration file in `.ci_support` to build packages for various platforms, Python versions, and optionally `gnuradio` versions (by adding to `gnuradio_extra_pin` in `recipe/conda_build_config.yaml`).
**You should repeat this step whenever the recipe is updated or when changes to the conda-forge infrastructure require all CI scripts to be updated.**
Since the newly created files will be rewritten whenever conda-smithy is run, you should not edit any of the automatically-generated files in e.g. `.ci_support`, `.scripts`, or `.github/workflows/conda-build.yml`.
4. (optional) If you want to enable uploads of the packages to [anaconda.org](https://anaconda.org) whenever the CI is run from a commit on the branch specified in `conda-forge.yml`, you need to set an Anaconda Cloud API token to the `BINSTAR_TOKEN` environment variable. To generate a token, follow the instructions [here](https://docs.anaconda.com/anacondaorg/user-guide/tasks/work-with-accounts/#creating-access-tokens). To populate the `BINSTAR_TOKEN` environment variable for CI jobs, add the token as a secret by following, for example, the [Github docs](https://docs.github.com/en/actions/reference/encrypted-secrets).

Wyświetl plik

@ -0,0 +1,30 @@
# See https://conda-forge.org/docs/maintainer/conda_forge_yml.html for
# documentation on possible keys and values.
# uncomment to enable cross-compiled osx-arm64 builds
#build_platform:
# osx_arm64: osx_64
clone_depth: 0
github_actions:
store_build_artifacts: true
os_version:
linux_64: cos7
provider:
linux: github_actions
osx: github_actions
win: github_actions
# uncomment to enable additional linux platforms
#linux_aarch64: github_actions
#linux_ppc64le: github_actions
recipe_dir: .conda/recipe
# skip unnecessary files since this is not a full-fledged conda-forge feedstock
skip_render:
- README.md
- LICENSE.txt
- .gitattributes
- .gitignore
- build-locally.py
- LICENSE
test: native_and_emulated
# enable uploads to Anaconda Cloud from specified branches only
upload_on_branch: main

Wyświetl plik

@ -0,0 +1,29 @@
setlocal EnableDelayedExpansion
@echo on
:: Make a build folder and change to it
cmake -E make_directory buildconda
cd buildconda
:: configure
cmake -G "Ninja" ^
-DCMAKE_BUILD_TYPE:STRING=Release ^
-DCMAKE_INSTALL_PREFIX:PATH="%LIBRARY_PREFIX%" ^
-DCMAKE_PREFIX_PATH:PATH="%LIBRARY_PREFIX%" ^
-DGR_PYTHON_DIR:PATH="%SP_DIR%" ^
-DENABLE_DOXYGEN=OFF ^
-DENABLE_TESTING=ON ^
..
if errorlevel 1 exit 1
:: build
cmake --build . --config Release -- -j%CPU_COUNT%
if errorlevel 1 exit 1
:: install
cmake --build . --config Release --target install
if errorlevel 1 exit 1
:: test
ctest --build-config Release --output-on-failure --timeout 120 -j%CPU_COUNT%
if errorlevel 1 exit 1

Wyświetl plik

@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -ex
cmake -E make_directory buildconda
cd buildconda
cmake_config_args=(
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_INSTALL_PREFIX=$PREFIX
-DLIB_SUFFIX=""
-DENABLE_DOXYGEN=OFF
-DENABLE_TESTING=ON
)
cmake ${CMAKE_ARGS} -G "Ninja" .. "${cmake_config_args[@]}"
cmake --build . --config Release -- -j${CPU_COUNT}
cmake --build . --config Release --target install
if [[ "${CONDA_BUILD_CROSS_COMPILATION:-}" != "1" || "${CROSSCOMPILING_EMULATOR}" != "" ]]; then
ctest --build-config Release --output-on-failure --timeout 120 -j${CPU_COUNT}
fi

Wyświetl plik

@ -0,0 +1,14 @@
# this is the channel and label where packages will be uploaded to if enabled
# (see ../README.md)
channel_targets:
- gnuradio main
# override the conda-forge pin for gnuradio-core by uncommenting
# and specifying a different version here
#gnuradio_core:
#- "3.10.1"
gnuradio_extra_pin:
# always leave one entry with the empty string
- ""
# add version strings here like to get builds for versions other than
# the conda-forge-wide default or version specified above for gnuradio_core
#- "3.9.5"

Wyświetl plik

@ -0,0 +1,88 @@
{% set oot_name = "droneid" %}
{% set name = "gnuradio-" + oot_name %}
{% set version = (environ.get("GIT_DESCRIBE_TAG_PEP440", "0.0.0." + datetime.datetime.now().strftime("%Y%m%d") + ".dev+" + environ.get("GIT_DESCRIBE_HASH", "local"))|string) %}
package:
name: {{ name|lower }}
version: {{ version }}
source:
# use local path or git repository depending on if the build is local or done on CI
path: "../.." # [not os.environ.get("CI")]
git_url: {{ environ.get('FEEDSTOCK_ROOT', "../..") }} # [os.environ.get("CI")]
build:
number: 0
requirements:
build:
- {{ compiler("c") }}
- {{ compiler("cxx") }}
- cmake
- git
- ninja
- pkg-config
# cross-compilation requirements
- python # [build_platform != target_platform]
- cross-python_{{ target_platform }} # [build_platform != target_platform]
- numpy # [build_platform != target_platform]
- pybind11 # [build_platform != target_platform]
# Add extra build tool dependencies here
host:
- gmp # [linux]
# the following two entries are for generating builds against specific GR versions
- gnuradio-core # [not gnuradio_extra_pin]
- gnuradio-core {{ gnuradio_extra_pin }}.* # [gnuradio_extra_pin]
- pip # [win]
- pybind11
- python
- numpy
- volk
# Add/remove library dependencies here
run:
- numpy
- python
# Add/remove runtime dependencies here
test:
commands:
# Add a list of commands to run to check that the package works. Examples below.
## verify that commands run
#- COMMAND --help
# verify that (some) headers get installed
- test -f $PREFIX/include/gnuradio/{{ oot_name }}/api.h # [not win]
- if not exist %PREFIX%\\Library\\include\\gnuradio\\{{ oot_name }}\\api.h exit 1 # [win]
## verify that libraries get installed
#- test -f $PREFIX/lib/lib{{ name }}${SHLIB_EXT} # [not win]
#- if not exist %PREFIX%\\Library\\bin\\{{ name }}.dll exit 1 # [win]
#- if not exist %PREFIX%\\Library\\lib\\{{ name }}.lib exit 1 # [win]
## verify that (some) GRC blocks get installed
#{% set blocks = ["LIST", "OF", "GRC", "BLOCK", "NAMES"] %}
#{% for block in blocks %}
#- test -f $PREFIX/share/gnuradio/grc/blocks/{{ block }}.block.yml # [not win]
#- if not exist %PREFIX%\\Library\\share\\gnuradio\\grc\\blocks\\{{ block }}.block.yml exit 1 # [win]
#{% endfor %}
imports:
# verify that the python module imports
- gnuradio.{{ oot_name }}
about:
# For licenses, use the SPDX identifier, e.g: "GPL-2.0-only" instead of
# "GNU General Public License version 2.0". See https://spdx.org/licenses/.
# Include the license text by using the license_file entry set to the path
# of the license text file within the source directory, e.g. "LICENSE".
# See https://docs.conda.io/projects/conda-build/en/latest/resources/define-metadata.html#license-file
#home: https://github.com/<username>/gr-droneid
#license: GPL-3.0-or-later
#license_file: LICENSE
#summary: GNU Radio droneid module
#description: >
# Short description of the gr-droneid module.

Wyświetl plik

@ -1,3 +0,0 @@
.idea/
build/
cmake-build-*/

Wyświetl plik

@ -1,22 +1,15 @@
# Copyright 2011,2012,2014,2016,2018 Free Software Foundation, Inc.
# Copyright 2011-2020 Free Software Foundation, Inc.
#
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-droneid
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
# SPDX-License-Identifier: GPL-3.0-or-later
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
# Select the release build type by default to get optimization flags.
# This has to come before project() which otherwise initializes it.
# Build type can still be overridden by setting -DCMAKE_BUILD_TYPE=
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "")
########################################################################
# Project setup
@ -25,29 +18,22 @@ cmake_minimum_required(VERSION 3.8)
project(gr-droneid CXX C)
enable_testing()
set(MATLAB_PATH "" CACHE STRING "Path to MATLAB installation")
# Install to PyBOMBS target prefix if defined
if(DEFINED ENV{PYBOMBS_PREFIX})
set(CMAKE_INSTALL_PREFIX $ENV{PYBOMBS_PREFIX})
message(STATUS "PyBOMBS installed GNU Radio. Setting CMAKE_INSTALL_PREFIX to $ENV{PYBOMBS_PREFIX}")
endif()
# Select the release build type by default to get optimization flags
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release")
message(STATUS "Build type not specified: defaulting to release.")
endif(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "")
# Make sure our local CMake Modules path comes first
list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/Modules)
list(INSERT CMAKE_MODULE_PATH 0 ${PROJECT_SOURCE_DIR}/cmake/Modules)
# Find gnuradio to get access to the cmake modules
find_package(Gnuradio "3.10" REQUIRED)
# Set the version information here
set(VERSION_MAJOR 1)
set(VERSION_API 0)
set(VERSION_ABI 0)
set(VERSION_PATCH git)
set(VERSION_PATCH 0)
cmake_policy(SET CMP0011 NEW)
@ -55,39 +41,20 @@ cmake_policy(SET CMP0011 NEW)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
########################################################################
# Compiler specific setup
# Minimum Version Requirements
########################################################################
if((CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR
CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
AND NOT WIN32)
#http://gcc.gnu.org/wiki/Visibility
add_definitions(-fvisibility=hidden)
endif()
IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
SET(CMAKE_CXX_STANDARD 11)
ELSEIF(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
SET(CMAKE_CXX_STANDARD 11)
ELSEIF(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
SET(CMAKE_CXX_STANDARD 11)
ELSE()
message(WARNING "C++ standard could not be set because compiler is not GNU, Clang or MSVC.")
ENDIF()
include(GrMinReq)
IF(CMAKE_C_COMPILER_ID STREQUAL "GNU")
SET(CMAKE_C_STANDARD 11)
ELSEIF(CMAKE_C_COMPILER_ID MATCHES "Clang")
SET(CMAKE_C_STANDARD 11)
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
SET(CMAKE_C_STANDARD 11)
ELSE()
message(WARNING "C standard could not be set because compiler is not GNU, Clang or MSVC.")
ENDIF()
########################################################################
# Compiler settings
########################################################################
include(GrCompilerSettings)
########################################################################
# Install directories
########################################################################
find_package(Gnuradio "3.8" REQUIRED fft filter blocks)
include(GrVersion)
include(GrPlatform) #define LIB_SUFFIX
@ -96,8 +63,8 @@ if(NOT CMAKE_MODULES_DIR)
set(CMAKE_MODULES_DIR lib${LIB_SUFFIX}/cmake)
endif(NOT CMAKE_MODULES_DIR)
set(GR_INCLUDE_DIR include/droneid)
set(GR_CMAKE_DIR ${CMAKE_MODULES_DIR}/droneid)
set(GR_INCLUDE_DIR include/gnuradio/droneid)
set(GR_CMAKE_DIR ${CMAKE_MODULES_DIR}/gnuradio-droneid)
set(GR_PKG_DATA_DIR ${GR_DATA_DIR}/${CMAKE_PROJECT_NAME})
set(GR_PKG_DOC_DIR ${GR_DOC_DIR}/${CMAKE_PROJECT_NAME})
set(GR_PKG_CONF_DIR ${GR_CONF_DIR}/${CMAKE_PROJECT_NAME}/conf.d)
@ -141,7 +108,7 @@ endif(DOXYGEN_FOUND)
# Create uninstall target
########################################################################
configure_file(
${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in
${PROJECT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake
@ONLY)
@ -149,22 +116,33 @@ add_custom_target(uninstall
${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake
)
########################################################################
# Add subdirectories
########################################################################
add_subdirectory(include/droneid)
add_subdirectory(include/gnuradio/droneid)
add_subdirectory(lib)
add_subdirectory(apps)
add_subdirectory(docs)
add_subdirectory(swig)
add_subdirectory(python)
add_subdirectory(grc)
# NOTE: manually update below to use GRC to generate C++ flowgraphs w/o python
if(ENABLE_PYTHON)
message(STATUS "PYTHON and GRC components are enabled")
add_subdirectory(python/droneid)
add_subdirectory(grc)
else(ENABLE_PYTHON)
message(STATUS "PYTHON and GRC components are disabled")
endif(ENABLE_PYTHON)
########################################################################
# Install cmake search helper for this library
########################################################################
install(FILES cmake/Modules/droneidConfig.cmake
DESTINATION ${CMAKE_MODULES_DIR}/droneid
install(FILES cmake/Modules/gnuradio-droneidConfig.cmake
DESTINATION ${GR_CMAKE_DIR}
)
include(CMakePackageConfigHelpers)
configure_package_config_file(
${PROJECT_SOURCE_DIR}/cmake/Modules/targetConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/cmake/Modules/${target}Config.cmake
INSTALL_DESTINATION ${GR_CMAKE_DIR}
)

Wyświetl plik

@ -3,20 +3,8 @@
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-droneid
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
# SPDX-License-Identifier: GPL-3.0-or-later
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
include(GrPython)

Wyświetl plik

@ -1,9 +1,10 @@
INCLUDE(FindPkgConfig)
PKG_CHECK_MODULES(PC_DRONEID droneid)
find_package(PkgConfig)
PKG_CHECK_MODULES(PC_GR_DRONEID gnuradio-droneid)
FIND_PATH(
DRONEID_INCLUDE_DIRS
NAMES droneid/api.h
GR_DRONEID_INCLUDE_DIRS
NAMES gnuradio/droneid/api.h
HINTS $ENV{DRONEID_DIR}/include
${PC_DRONEID_INCLUDEDIR}
PATHS ${CMAKE_INSTALL_PREFIX}/include
@ -12,7 +13,7 @@ FIND_PATH(
)
FIND_LIBRARY(
DRONEID_LIBRARIES
GR_DRONEID_LIBRARIES
NAMES gnuradio-droneid
HINTS $ENV{DRONEID_DIR}/lib
${PC_DRONEID_LIBDIR}
@ -24,8 +25,8 @@ FIND_LIBRARY(
/usr/lib64
)
include("${CMAKE_CURRENT_LIST_DIR}/droneidTarget.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/gnuradio-droneidTarget.cmake")
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(DRONEID DEFAULT_MSG DRONEID_LIBRARIES DRONEID_INCLUDE_DIRS)
MARK_AS_ADVANCED(DRONEID_LIBRARIES DRONEID_INCLUDE_DIRS)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GR_DRONEID DEFAULT_MSG GR_DRONEID_LIBRARIES GR_DRONEID_INCLUDE_DIRS)
MARK_AS_ADVANCED(GR_DRONEID_LIBRARIES GR_DRONEID_INCLUDE_DIRS)

Wyświetl plik

@ -2,20 +2,8 @@
#
# This file is part of GNU Radio
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
# SPDX-License-Identifier: GPL-3.0-or-later
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
include(CMakeFindDependencyMacro)

Wyświetl plik

@ -3,20 +3,8 @@
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-droneid
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
# SPDX-License-Identifier: GPL-3.0-or-later
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
########################################################################
# Setup dependencies

Wyświetl plik

@ -3,32 +3,21 @@
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-droneid
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
# SPDX-License-Identifier: GPL-3.0-or-later
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
########################################################################
# Create the doxygen configuration file
########################################################################
file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} top_srcdir)
file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} top_builddir)
file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} abs_top_srcdir)
file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} abs_top_builddir)
file(TO_NATIVE_PATH ${PROJECT_SOURCE_DIR} top_srcdir)
file(TO_NATIVE_PATH ${PROJECT_BINARY_DIR} top_builddir)
file(TO_NATIVE_PATH ${PROJECT_SOURCE_DIR} abs_top_srcdir)
file(TO_NATIVE_PATH ${PROJECT_BINARY_DIR} abs_top_builddir)
set(HAVE_DOT ${DOXYGEN_DOT_FOUND})
set(enable_html_docs YES)
set(enable_latex_docs NO)
set(enable_mathjax NO)
set(enable_xml_docs YES)
configure_file(

Wyświetl plik

@ -199,13 +199,6 @@ TAB_SIZE = 8
ALIASES =
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding
# "class=itcl::class" will allow you to use the command class in the
# itcl::class meaning.
TCL_SUBST =
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
# sources only. Doxygen will then generate output that is more tailored for C.
# For instance, some of the names that are used will be different. The list
@ -723,8 +716,6 @@ EXCLUDE_PATTERNS = */.deps/* \
EXCLUDE_SYMBOLS = ad9862 \
numpy \
*swig* \
*Swig* \
*my_top_block* \
*my_graph* \
*app_top_block* \
@ -790,7 +781,7 @@ INPUT_FILTER =
# info on how filters are used. If FILTER_PATTERNS is empty or if
# non of the patterns match the file name, INPUT_FILTER is applied.
FILTER_PATTERNS = *.py="@top_srcdir@"/doc/doxygen/other/doxypy.py
FILTER_PATTERNS = *.py=@top_srcdir@/docs/doxygen/other/doxypy.py
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
# INPUT_FILTER) will be used to filter the input files when producing source
@ -879,12 +870,6 @@ VERBATIM_HEADERS = YES
ALPHABETICAL_INDEX = YES
# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
# in which this list will be split (can be a number in the range [1..20])
COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all
# classes will be put under the same header in the alphabetical index.
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
@ -1220,14 +1205,14 @@ FORMULA_TRANSPARENT = YES
# output. When enabled you may also need to install MathJax separately and
# configure the path to it using the MATHJAX_RELPATH option.
USE_MATHJAX = NO
USE_MATHJAX = @enable_mathjax@
# When MathJax is enabled you can set the default output format to be used for
# the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and
# SVG. The default value is HTML-CSS, which is slower, but has the best
# compatibility.
MATHJAX_FORMAT = HTML-CSS
MATHJAX_FORMAT = SVG
# When MathJax is enabled you need to specify the location relative to the
# HTML output directory using the MATHJAX_RELPATH option. The destination
@ -1239,12 +1224,12 @@ MATHJAX_FORMAT = HTML-CSS
# However, it is strongly recommended to install a local
# copy of MathJax from http://www.mathjax.org before deployment.
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
MATHJAX_RELPATH = @MATHJAX2_PATH@
# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
# names that should be enabled during MathJax rendering.
MATHJAX_EXTENSIONS =
MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript
# pieces of code that will be used on startup of the MathJax code.
@ -1680,11 +1665,6 @@ EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
# The PERL_PATH should be the absolute path and name of the perl script
# interpreter (i.e. the result of `which perl').
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
@ -1697,15 +1677,6 @@ PERL_PATH = /usr/bin/perl
CLASS_DIAGRAMS = YES
# You can define message sequence charts within doxygen comments using the \msc
# command. Doxygen will then run the mscgen tool (see
# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
# documentation. The MSCGEN_PATH tag allows you to specify the directory where
# the mscgen tool resides. If left empty the tool is assumed to be found in the
# default search path.
MSCGEN_PATH =
# If set to YES, the inheritance and collaboration graphs will hide
# inheritance and usage relations if the target is undocumented
# or is not a class.
@ -1834,7 +1805,7 @@ DIRECTORY_GRAPH = YES
# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
# visible in IE 9+ (other browsers do not have this requirement).
DOT_IMAGE_FORMAT = png
DOT_IMAGE_FORMAT = svg
# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
# enable generation of interactive SVG images that allow zooming and panning.

Wyświetl plik

@ -4,20 +4,8 @@
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-droneid
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
# SPDX-License-Identifier: GPL-3.0-or-later
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
"""
Python interface to contents of doxygen xml documentation.
@ -64,10 +52,10 @@ This line is uninformative and is only to test line breaks in the comments.
u'Outputs the vital aadvark statistics.'
"""
from __future__ import unicode_literals
from .doxyindex import DoxyIndex, DoxyFunction, DoxyParam, DoxyClass, DoxyFile, DoxyNamespace, DoxyGroup, DoxyFriend, DoxyOther
def _test():
import os
this_dir = os.path.dirname(globals()['__file__'])
@ -79,6 +67,6 @@ def _test():
import doctest
return doctest.testmod()
if __name__ == "__main__":
_test()

Wyświetl plik

@ -4,20 +4,8 @@
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-droneid
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
# SPDX-License-Identifier: GPL-3.0-or-later
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
"""
A base class is created.
@ -25,8 +13,6 @@ A base class is created.
Classes based upon this are used to make more user-friendly interfaces
to the doxygen xml docs than the generated classes provide.
"""
from __future__ import print_function
from __future__ import unicode_literals
import os
import pdb
@ -97,8 +83,8 @@ class Base(object):
for cls in self.mem_classes:
if cls.can_parse(mem):
return cls
raise Exception(("Did not find a class for object '%s'." \
% (mem.get_name())))
raise Exception(("Did not find a class for object '%s'."
% (mem.get_name())))
def convert_mem(self, mem):
try:

Wyświetl plik

@ -4,27 +4,13 @@
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-droneid
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
# SPDX-License-Identifier: GPL-3.0-or-later
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
"""
Classes providing more user-friendly interfaces to the doxygen xml
docs than the generated classes provide.
"""
from __future__ import absolute_import
from __future__ import unicode_literals
import os
@ -32,6 +18,7 @@ from .generated import index
from .base import Base
from .text import description
class DoxyIndex(Base):
"""
Parses a doxygen xml directory.
@ -60,17 +47,8 @@ class DoxyIndex(Base):
self._members.append(converted)
def generate_swig_doc_i(self):
"""
%feature("docstring") gr_make_align_on_samplenumbers_ss::align_state "
Wraps the C++: gr_align_on_samplenumbers_ss::align_state";
"""
pass
class DoxyCompMem(Base):
kind = None
def __init__(self, *args, **kwargs):
@ -106,9 +84,11 @@ class DoxyCompMem(Base):
class DoxyCompound(DoxyCompMem):
pass
class DoxyMember(DoxyCompMem):
pass
class DoxyFunction(DoxyMember):
__module__ = "gnuradio.utils.doxyxml"
@ -129,9 +109,11 @@ class DoxyFunction(DoxyMember):
self._data['params'].append(DoxyParam(prm))
brief_description = property(lambda self: self.data()['brief_description'])
detailed_description = property(lambda self: self.data()['detailed_description'])
detailed_description = property(
lambda self: self.data()['detailed_description'])
params = property(lambda self: self.data()['params'])
Base.mem_classes.append(DoxyFunction)
@ -156,9 +138,11 @@ class DoxyParam(DoxyMember):
return '\n\n'.join(descriptions)
brief_description = property(lambda self: self.data()['brief_description'])
detailed_description = property(lambda self: self.data()['detailed_description'])
detailed_description = property(
lambda self: self.data()['detailed_description'])
name = property(lambda self: self.data()['declname'])
class DoxyParameterItem(DoxyMember):
"""A different representation of a parameter in Doxygen."""
@ -200,9 +184,11 @@ class DoxyClass(DoxyCompound):
self.process_memberdefs()
brief_description = property(lambda self: self.data()['brief_description'])
detailed_description = property(lambda self: self.data()['detailed_description'])
detailed_description = property(
lambda self: self.data()['detailed_description'])
params = property(lambda self: self.data()['params'])
Base.mem_classes.append(DoxyClass)
@ -223,7 +209,9 @@ class DoxyFile(DoxyCompound):
self.process_memberdefs()
brief_description = property(lambda self: self.data()['brief_description'])
detailed_description = property(lambda self: self.data()['detailed_description'])
detailed_description = property(
lambda self: self.data()['detailed_description'])
Base.mem_classes.append(DoxyFile)
@ -244,6 +232,7 @@ class DoxyNamespace(DoxyCompound):
return
self.process_memberdefs()
Base.mem_classes.append(DoxyNamespace)
@ -287,6 +276,7 @@ class DoxyFriend(DoxyMember):
kind = 'friend'
Base.mem_classes.append(DoxyFriend)
@ -301,4 +291,5 @@ class DoxyOther(Base):
def can_parse(cls, obj):
return obj.kind in cls.kinds
Base.mem_classes.append(DoxyOther)

Wyświetl plik

@ -5,4 +5,3 @@ These do the real work of parsing the doxygen xml files but the
resultant classes are not very friendly to navigate so the rest of the
doxyxml module processes them further.
"""
from __future__ import unicode_literals

Wyświetl plik

@ -3,8 +3,6 @@
"""
Generated Mon Feb 9 19:08:05 2009 by generateDS.py.
"""
from __future__ import absolute_import
from __future__ import unicode_literals
from xml.dom import minidom
@ -24,13 +22,15 @@ class DoxygenTypeSub(supermod.DoxygenType):
return self.compounddef.find(details)
supermod.DoxygenType.subclass = DoxygenTypeSub
# end class DoxygenTypeSub
class compounddefTypeSub(supermod.compounddefType):
def __init__(self, kind=None, prot=None, id=None, compoundname='', title='', basecompoundref=None, derivedcompoundref=None, includes=None, includedby=None, incdepgraph=None, invincdepgraph=None, innerdir=None, innerfile=None, innerclass=None, innernamespace=None, innerpage=None, innergroup=None, templateparamlist=None, sectiondef=None, briefdescription=None, detaileddescription=None, inheritancegraph=None, collaborationgraph=None, programlisting=None, location=None, listofallmembers=None):
supermod.compounddefType.__init__(self, kind, prot, id, compoundname, title, basecompoundref, derivedcompoundref, includes, includedby, incdepgraph, invincdepgraph, innerdir, innerfile, innerclass, innernamespace, innerpage, innergroup, templateparamlist, sectiondef, briefdescription, detaileddescription, inheritancegraph, collaborationgraph, programlisting, location, listofallmembers)
supermod.compounddefType.__init__(self, kind, prot, id, compoundname, title, basecompoundref, derivedcompoundref, includes, includedby, incdepgraph, invincdepgraph, innerdir, innerfile, innerclass,
innernamespace, innerpage, innergroup, templateparamlist, sectiondef, briefdescription, detaileddescription, inheritancegraph, collaborationgraph, programlisting, location, listofallmembers)
def find(self, details):
@ -50,13 +50,18 @@ supermod.compounddefType.subclass = compounddefTypeSub
class listofallmembersTypeSub(supermod.listofallmembersType):
def __init__(self, member=None):
supermod.listofallmembersType.__init__(self, member)
supermod.listofallmembersType.subclass = listofallmembersTypeSub
# end class listofallmembersTypeSub
class memberRefTypeSub(supermod.memberRefType):
def __init__(self, virt=None, prot=None, refid=None, ambiguityscope=None, scope='', name=''):
supermod.memberRefType.__init__(self, virt, prot, refid, ambiguityscope, scope, name)
supermod.memberRefType.__init__(
self, virt, prot, refid, ambiguityscope, scope, name)
supermod.memberRefType.subclass = memberRefTypeSub
# end class memberRefTypeSub
@ -64,6 +69,8 @@ supermod.memberRefType.subclass = memberRefTypeSub
class compoundRefTypeSub(supermod.compoundRefType):
def __init__(self, virt=None, prot=None, refid=None, valueOf_='', mixedclass_=None, content_=None):
supermod.compoundRefType.__init__(self, mixedclass_, content_)
supermod.compoundRefType.subclass = compoundRefTypeSub
# end class compoundRefTypeSub
@ -71,6 +78,8 @@ supermod.compoundRefType.subclass = compoundRefTypeSub
class reimplementTypeSub(supermod.reimplementType):
def __init__(self, refid=None, valueOf_='', mixedclass_=None, content_=None):
supermod.reimplementType.__init__(self, mixedclass_, content_)
supermod.reimplementType.subclass = reimplementTypeSub
# end class reimplementTypeSub
@ -78,6 +87,8 @@ supermod.reimplementType.subclass = reimplementTypeSub
class incTypeSub(supermod.incType):
def __init__(self, local=None, refid=None, valueOf_='', mixedclass_=None, content_=None):
supermod.incType.__init__(self, mixedclass_, content_)
supermod.incType.subclass = incTypeSub
# end class incTypeSub
@ -85,23 +96,26 @@ supermod.incType.subclass = incTypeSub
class refTypeSub(supermod.refType):
def __init__(self, prot=None, refid=None, valueOf_='', mixedclass_=None, content_=None):
supermod.refType.__init__(self, mixedclass_, content_)
supermod.refType.subclass = refTypeSub
# end class refTypeSub
class refTextTypeSub(supermod.refTextType):
def __init__(self, refid=None, kindref=None, external=None, valueOf_='', mixedclass_=None, content_=None):
supermod.refTextType.__init__(self, mixedclass_, content_)
supermod.refTextType.subclass = refTextTypeSub
# end class refTextTypeSub
class sectiondefTypeSub(supermod.sectiondefType):
def __init__(self, kind=None, header='', description=None, memberdef=None):
supermod.sectiondefType.__init__(self, kind, header, description, memberdef)
supermod.sectiondefType.__init__(
self, kind, header, description, memberdef)
def find(self, details):
@ -118,7 +132,10 @@ supermod.sectiondefType.subclass = sectiondefTypeSub
class memberdefTypeSub(supermod.memberdefType):
def __init__(self, initonly=None, kind=None, volatile=None, const=None, raise_=None, virt=None, readable=None, prot=None, explicit=None, new=None, final=None, writable=None, add=None, static=None, remove=None, sealed=None, mutable=None, gettable=None, inline=None, settable=None, id=None, templateparamlist=None, type_=None, definition='', argsstring='', name='', read='', write='', bitfield='', reimplements=None, reimplementedby=None, param=None, enumvalue=None, initializer=None, exceptions=None, briefdescription=None, detaileddescription=None, inbodydescription=None, location=None, references=None, referencedby=None):
supermod.memberdefType.__init__(self, initonly, kind, volatile, const, raise_, virt, readable, prot, explicit, new, final, writable, add, static, remove, sealed, mutable, gettable, inline, settable, id, templateparamlist, type_, definition, argsstring, name, read, write, bitfield, reimplements, reimplementedby, param, enumvalue, initializer, exceptions, briefdescription, detaileddescription, inbodydescription, location, references, referencedby)
supermod.memberdefType.__init__(self, initonly, kind, volatile, const, raise_, virt, readable, prot, explicit, new, final, writable, add, static, remove, sealed, mutable, gettable, inline, settable, id, templateparamlist, type_,
definition, argsstring, name, read, write, bitfield, reimplements, reimplementedby, param, enumvalue, initializer, exceptions, briefdescription, detaileddescription, inbodydescription, location, references, referencedby)
supermod.memberdefType.subclass = memberdefTypeSub
# end class memberdefTypeSub
@ -126,6 +143,8 @@ supermod.memberdefType.subclass = memberdefTypeSub
class descriptionTypeSub(supermod.descriptionType):
def __init__(self, title='', para=None, sect1=None, internal=None, mixedclass_=None, content_=None):
supermod.descriptionType.__init__(self, mixedclass_, content_)
supermod.descriptionType.subclass = descriptionTypeSub
# end class descriptionTypeSub
@ -133,6 +152,8 @@ supermod.descriptionType.subclass = descriptionTypeSub
class enumvalueTypeSub(supermod.enumvalueType):
def __init__(self, prot=None, id=None, name='', initializer=None, briefdescription=None, detaileddescription=None, mixedclass_=None, content_=None):
supermod.enumvalueType.__init__(self, mixedclass_, content_)
supermod.enumvalueType.subclass = enumvalueTypeSub
# end class enumvalueTypeSub
@ -140,13 +161,18 @@ supermod.enumvalueType.subclass = enumvalueTypeSub
class templateparamlistTypeSub(supermod.templateparamlistType):
def __init__(self, param=None):
supermod.templateparamlistType.__init__(self, param)
supermod.templateparamlistType.subclass = templateparamlistTypeSub
# end class templateparamlistTypeSub
class paramTypeSub(supermod.paramType):
def __init__(self, type_=None, declname='', defname='', array='', defval=None, briefdescription=None):
supermod.paramType.__init__(self, type_, declname, defname, array, defval, briefdescription)
supermod.paramType.__init__(
self, type_, declname, defname, array, defval, briefdescription)
supermod.paramType.subclass = paramTypeSub
# end class paramTypeSub
@ -154,6 +180,8 @@ supermod.paramType.subclass = paramTypeSub
class linkedTextTypeSub(supermod.linkedTextType):
def __init__(self, ref=None, mixedclass_=None, content_=None):
supermod.linkedTextType.__init__(self, mixedclass_, content_)
supermod.linkedTextType.subclass = linkedTextTypeSub
# end class linkedTextTypeSub
@ -161,6 +189,8 @@ supermod.linkedTextType.subclass = linkedTextTypeSub
class graphTypeSub(supermod.graphType):
def __init__(self, node=None):
supermod.graphType.__init__(self, node)
supermod.graphType.subclass = graphTypeSub
# end class graphTypeSub
@ -168,6 +198,8 @@ supermod.graphType.subclass = graphTypeSub
class nodeTypeSub(supermod.nodeType):
def __init__(self, id=None, label='', link=None, childnode=None):
supermod.nodeType.__init__(self, id, label, link, childnode)
supermod.nodeType.subclass = nodeTypeSub
# end class nodeTypeSub
@ -175,6 +207,8 @@ supermod.nodeType.subclass = nodeTypeSub
class childnodeTypeSub(supermod.childnodeType):
def __init__(self, relation=None, refid=None, edgelabel=None):
supermod.childnodeType.__init__(self, relation, refid, edgelabel)
supermod.childnodeType.subclass = childnodeTypeSub
# end class childnodeTypeSub
@ -182,6 +216,8 @@ supermod.childnodeType.subclass = childnodeTypeSub
class linkTypeSub(supermod.linkType):
def __init__(self, refid=None, external=None, valueOf_=''):
supermod.linkType.__init__(self, refid, external)
supermod.linkType.subclass = linkTypeSub
# end class linkTypeSub
@ -189,13 +225,18 @@ supermod.linkType.subclass = linkTypeSub
class listingTypeSub(supermod.listingType):
def __init__(self, codeline=None):
supermod.listingType.__init__(self, codeline)
supermod.listingType.subclass = listingTypeSub
# end class listingTypeSub
class codelineTypeSub(supermod.codelineType):
def __init__(self, external=None, lineno=None, refkind=None, refid=None, highlight=None):
supermod.codelineType.__init__(self, external, lineno, refkind, refid, highlight)
supermod.codelineType.__init__(
self, external, lineno, refkind, refid, highlight)
supermod.codelineType.subclass = codelineTypeSub
# end class codelineTypeSub
@ -203,6 +244,8 @@ supermod.codelineType.subclass = codelineTypeSub
class highlightTypeSub(supermod.highlightType):
def __init__(self, class_=None, sp=None, ref=None, mixedclass_=None, content_=None):
supermod.highlightType.__init__(self, mixedclass_, content_)
supermod.highlightType.subclass = highlightTypeSub
# end class highlightTypeSub
@ -210,13 +253,18 @@ supermod.highlightType.subclass = highlightTypeSub
class referenceTypeSub(supermod.referenceType):
def __init__(self, endline=None, startline=None, refid=None, compoundref=None, valueOf_='', mixedclass_=None, content_=None):
supermod.referenceType.__init__(self, mixedclass_, content_)
supermod.referenceType.subclass = referenceTypeSub
# end class referenceTypeSub
class locationTypeSub(supermod.locationType):
def __init__(self, bodystart=None, line=None, bodyend=None, bodyfile=None, file=None, valueOf_=''):
supermod.locationType.__init__(self, bodystart, line, bodyend, bodyfile, file)
supermod.locationType.__init__(
self, bodystart, line, bodyend, bodyfile, file)
supermod.locationType.subclass = locationTypeSub
# end class locationTypeSub
@ -224,6 +272,8 @@ supermod.locationType.subclass = locationTypeSub
class docSect1TypeSub(supermod.docSect1Type):
def __init__(self, id=None, title='', para=None, sect2=None, internal=None, mixedclass_=None, content_=None):
supermod.docSect1Type.__init__(self, mixedclass_, content_)
supermod.docSect1Type.subclass = docSect1TypeSub
# end class docSect1TypeSub
@ -231,6 +281,8 @@ supermod.docSect1Type.subclass = docSect1TypeSub
class docSect2TypeSub(supermod.docSect2Type):
def __init__(self, id=None, title='', para=None, sect3=None, internal=None, mixedclass_=None, content_=None):
supermod.docSect2Type.__init__(self, mixedclass_, content_)
supermod.docSect2Type.subclass = docSect2TypeSub
# end class docSect2TypeSub
@ -238,6 +290,8 @@ supermod.docSect2Type.subclass = docSect2TypeSub
class docSect3TypeSub(supermod.docSect3Type):
def __init__(self, id=None, title='', para=None, sect4=None, internal=None, mixedclass_=None, content_=None):
supermod.docSect3Type.__init__(self, mixedclass_, content_)
supermod.docSect3Type.subclass = docSect3TypeSub
# end class docSect3TypeSub
@ -245,6 +299,8 @@ supermod.docSect3Type.subclass = docSect3TypeSub
class docSect4TypeSub(supermod.docSect4Type):
def __init__(self, id=None, title='', para=None, internal=None, mixedclass_=None, content_=None):
supermod.docSect4Type.__init__(self, mixedclass_, content_)
supermod.docSect4Type.subclass = docSect4TypeSub
# end class docSect4TypeSub
@ -252,6 +308,8 @@ supermod.docSect4Type.subclass = docSect4TypeSub
class docInternalTypeSub(supermod.docInternalType):
def __init__(self, para=None, sect1=None, mixedclass_=None, content_=None):
supermod.docInternalType.__init__(self, mixedclass_, content_)
supermod.docInternalType.subclass = docInternalTypeSub
# end class docInternalTypeSub
@ -259,6 +317,8 @@ supermod.docInternalType.subclass = docInternalTypeSub
class docInternalS1TypeSub(supermod.docInternalS1Type):
def __init__(self, para=None, sect2=None, mixedclass_=None, content_=None):
supermod.docInternalS1Type.__init__(self, mixedclass_, content_)
supermod.docInternalS1Type.subclass = docInternalS1TypeSub
# end class docInternalS1TypeSub
@ -266,6 +326,8 @@ supermod.docInternalS1Type.subclass = docInternalS1TypeSub
class docInternalS2TypeSub(supermod.docInternalS2Type):
def __init__(self, para=None, sect3=None, mixedclass_=None, content_=None):
supermod.docInternalS2Type.__init__(self, mixedclass_, content_)
supermod.docInternalS2Type.subclass = docInternalS2TypeSub
# end class docInternalS2TypeSub
@ -273,6 +335,8 @@ supermod.docInternalS2Type.subclass = docInternalS2TypeSub
class docInternalS3TypeSub(supermod.docInternalS3Type):
def __init__(self, para=None, sect3=None, mixedclass_=None, content_=None):
supermod.docInternalS3Type.__init__(self, mixedclass_, content_)
supermod.docInternalS3Type.subclass = docInternalS3TypeSub
# end class docInternalS3TypeSub
@ -280,6 +344,8 @@ supermod.docInternalS3Type.subclass = docInternalS3TypeSub
class docInternalS4TypeSub(supermod.docInternalS4Type):
def __init__(self, para=None, mixedclass_=None, content_=None):
supermod.docInternalS4Type.__init__(self, mixedclass_, content_)
supermod.docInternalS4Type.subclass = docInternalS4TypeSub
# end class docInternalS4TypeSub
@ -287,6 +353,8 @@ supermod.docInternalS4Type.subclass = docInternalS4TypeSub
class docURLLinkSub(supermod.docURLLink):
def __init__(self, url=None, valueOf_='', mixedclass_=None, content_=None):
supermod.docURLLink.__init__(self, mixedclass_, content_)
supermod.docURLLink.subclass = docURLLinkSub
# end class docURLLinkSub
@ -294,6 +362,8 @@ supermod.docURLLink.subclass = docURLLinkSub
class docAnchorTypeSub(supermod.docAnchorType):
def __init__(self, id=None, valueOf_='', mixedclass_=None, content_=None):
supermod.docAnchorType.__init__(self, mixedclass_, content_)
supermod.docAnchorType.subclass = docAnchorTypeSub
# end class docAnchorTypeSub
@ -301,6 +371,8 @@ supermod.docAnchorType.subclass = docAnchorTypeSub
class docFormulaTypeSub(supermod.docFormulaType):
def __init__(self, id=None, valueOf_='', mixedclass_=None, content_=None):
supermod.docFormulaType.__init__(self, mixedclass_, content_)
supermod.docFormulaType.subclass = docFormulaTypeSub
# end class docFormulaTypeSub
@ -308,6 +380,8 @@ supermod.docFormulaType.subclass = docFormulaTypeSub
class docIndexEntryTypeSub(supermod.docIndexEntryType):
def __init__(self, primaryie='', secondaryie=''):
supermod.docIndexEntryType.__init__(self, primaryie, secondaryie)
supermod.docIndexEntryType.subclass = docIndexEntryTypeSub
# end class docIndexEntryTypeSub
@ -315,6 +389,8 @@ supermod.docIndexEntryType.subclass = docIndexEntryTypeSub
class docListTypeSub(supermod.docListType):
def __init__(self, listitem=None):
supermod.docListType.__init__(self, listitem)
supermod.docListType.subclass = docListTypeSub
# end class docListTypeSub
@ -322,6 +398,8 @@ supermod.docListType.subclass = docListTypeSub
class docListItemTypeSub(supermod.docListItemType):
def __init__(self, para=None):
supermod.docListItemType.__init__(self, para)
supermod.docListItemType.subclass = docListItemTypeSub
# end class docListItemTypeSub
@ -329,6 +407,8 @@ supermod.docListItemType.subclass = docListItemTypeSub
class docSimpleSectTypeSub(supermod.docSimpleSectType):
def __init__(self, kind=None, title=None, para=None):
supermod.docSimpleSectType.__init__(self, kind, title, para)
supermod.docSimpleSectType.subclass = docSimpleSectTypeSub
# end class docSimpleSectTypeSub
@ -336,6 +416,8 @@ supermod.docSimpleSectType.subclass = docSimpleSectTypeSub
class docVarListEntryTypeSub(supermod.docVarListEntryType):
def __init__(self, term=None):
supermod.docVarListEntryType.__init__(self, term)
supermod.docVarListEntryType.subclass = docVarListEntryTypeSub
# end class docVarListEntryTypeSub
@ -343,6 +425,8 @@ supermod.docVarListEntryType.subclass = docVarListEntryTypeSub
class docRefTextTypeSub(supermod.docRefTextType):
def __init__(self, refid=None, kindref=None, external=None, valueOf_='', mixedclass_=None, content_=None):
supermod.docRefTextType.__init__(self, mixedclass_, content_)
supermod.docRefTextType.subclass = docRefTextTypeSub
# end class docRefTextTypeSub
@ -350,6 +434,8 @@ supermod.docRefTextType.subclass = docRefTextTypeSub
class docTableTypeSub(supermod.docTableType):
def __init__(self, rows=None, cols=None, row=None, caption=None):
supermod.docTableType.__init__(self, rows, cols, row, caption)
supermod.docTableType.subclass = docTableTypeSub
# end class docTableTypeSub
@ -357,6 +443,8 @@ supermod.docTableType.subclass = docTableTypeSub
class docRowTypeSub(supermod.docRowType):
def __init__(self, entry=None):
supermod.docRowType.__init__(self, entry)
supermod.docRowType.subclass = docRowTypeSub
# end class docRowTypeSub
@ -364,6 +452,8 @@ supermod.docRowType.subclass = docRowTypeSub
class docEntryTypeSub(supermod.docEntryType):
def __init__(self, thead=None, para=None):
supermod.docEntryType.__init__(self, thead, para)
supermod.docEntryType.subclass = docEntryTypeSub
# end class docEntryTypeSub
@ -371,6 +461,8 @@ supermod.docEntryType.subclass = docEntryTypeSub
class docHeadingTypeSub(supermod.docHeadingType):
def __init__(self, level=None, valueOf_='', mixedclass_=None, content_=None):
supermod.docHeadingType.__init__(self, mixedclass_, content_)
supermod.docHeadingType.subclass = docHeadingTypeSub
# end class docHeadingTypeSub
@ -378,6 +470,8 @@ supermod.docHeadingType.subclass = docHeadingTypeSub
class docImageTypeSub(supermod.docImageType):
def __init__(self, width=None, type_=None, name=None, height=None, valueOf_='', mixedclass_=None, content_=None):
supermod.docImageType.__init__(self, mixedclass_, content_)
supermod.docImageType.subclass = docImageTypeSub
# end class docImageTypeSub
@ -385,6 +479,8 @@ supermod.docImageType.subclass = docImageTypeSub
class docDotFileTypeSub(supermod.docDotFileType):
def __init__(self, name=None, valueOf_='', mixedclass_=None, content_=None):
supermod.docDotFileType.__init__(self, mixedclass_, content_)
supermod.docDotFileType.subclass = docDotFileTypeSub
# end class docDotFileTypeSub
@ -392,6 +488,8 @@ supermod.docDotFileType.subclass = docDotFileTypeSub
class docTocItemTypeSub(supermod.docTocItemType):
def __init__(self, id=None, valueOf_='', mixedclass_=None, content_=None):
supermod.docTocItemType.__init__(self, mixedclass_, content_)
supermod.docTocItemType.subclass = docTocItemTypeSub
# end class docTocItemTypeSub
@ -399,6 +497,8 @@ supermod.docTocItemType.subclass = docTocItemTypeSub
class docTocListTypeSub(supermod.docTocListType):
def __init__(self, tocitem=None):
supermod.docTocListType.__init__(self, tocitem)
supermod.docTocListType.subclass = docTocListTypeSub
# end class docTocListTypeSub
@ -406,6 +506,8 @@ supermod.docTocListType.subclass = docTocListTypeSub
class docLanguageTypeSub(supermod.docLanguageType):
def __init__(self, langid=None, para=None):
supermod.docLanguageType.__init__(self, langid, para)
supermod.docLanguageType.subclass = docLanguageTypeSub
# end class docLanguageTypeSub
@ -413,13 +515,18 @@ supermod.docLanguageType.subclass = docLanguageTypeSub
class docParamListTypeSub(supermod.docParamListType):
def __init__(self, kind=None, parameteritem=None):
supermod.docParamListType.__init__(self, kind, parameteritem)
supermod.docParamListType.subclass = docParamListTypeSub
# end class docParamListTypeSub
class docParamListItemSub(supermod.docParamListItem):
def __init__(self, parameternamelist=None, parameterdescription=None):
supermod.docParamListItem.__init__(self, parameternamelist, parameterdescription)
supermod.docParamListItem.__init__(
self, parameternamelist, parameterdescription)
supermod.docParamListItem.subclass = docParamListItemSub
# end class docParamListItemSub
@ -427,6 +534,8 @@ supermod.docParamListItem.subclass = docParamListItemSub
class docParamNameListSub(supermod.docParamNameList):
def __init__(self, parametername=None):
supermod.docParamNameList.__init__(self, parametername)
supermod.docParamNameList.subclass = docParamNameListSub
# end class docParamNameListSub
@ -434,6 +543,8 @@ supermod.docParamNameList.subclass = docParamNameListSub
class docParamNameSub(supermod.docParamName):
def __init__(self, direction=None, ref=None, mixedclass_=None, content_=None):
supermod.docParamName.__init__(self, mixedclass_, content_)
supermod.docParamName.subclass = docParamNameSub
# end class docParamNameSub
@ -441,6 +552,8 @@ supermod.docParamName.subclass = docParamNameSub
class docXRefSectTypeSub(supermod.docXRefSectType):
def __init__(self, id=None, xreftitle=None, xrefdescription=None):
supermod.docXRefSectType.__init__(self, id, xreftitle, xrefdescription)
supermod.docXRefSectType.subclass = docXRefSectTypeSub
# end class docXRefSectTypeSub
@ -448,6 +561,8 @@ supermod.docXRefSectType.subclass = docXRefSectTypeSub
class docCopyTypeSub(supermod.docCopyType):
def __init__(self, link=None, para=None, sect1=None, internal=None):
supermod.docCopyType.__init__(self, link, para, sect1, internal)
supermod.docCopyType.subclass = docCopyTypeSub
# end class docCopyTypeSub
@ -455,9 +570,12 @@ supermod.docCopyType.subclass = docCopyTypeSub
class docCharTypeSub(supermod.docCharType):
def __init__(self, char=None, valueOf_=''):
supermod.docCharType.__init__(self, char)
supermod.docCharType.subclass = docCharTypeSub
# end class docCharTypeSub
class docParaTypeSub(supermod.docParaType):
def __init__(self, char=None, valueOf_=''):
supermod.docParaType.__init__(self, char)
@ -471,7 +589,7 @@ class docParaTypeSub(supermod.docParaType):
if child_.nodeType == Node.TEXT_NODE:
obj_ = self.mixedclass_(MixedContainer.CategoryText,
MixedContainer.TypeNone, '', child_.nodeValue)
MixedContainer.TypeNone, '', child_.nodeValue)
self.content.append(obj_)
elif child_.nodeType == Node.ELEMENT_NODE and \
nodeName_ == "ref":
@ -494,12 +612,9 @@ supermod.docParaType.subclass = docParaTypeSub
# end class docParaTypeSub
def parse(inFilename):
doc = minidom.parse(inFilename)
rootNode = doc.documentElement
rootObj = supermod.DoxygenType.factory()
rootObj.build(rootNode)
return rootObj

Wyświetl plik

@ -3,8 +3,6 @@
"""
Generated Mon Feb 9 19:08:05 2009 by generateDS.py.
"""
from __future__ import absolute_import
from __future__ import unicode_literals
from xml.dom import minidom
@ -14,6 +12,7 @@ from . import compound
from . import indexsuper as supermod
class DoxygenTypeSub(supermod.DoxygenType):
def __init__(self, version=None, compound=None):
supermod.DoxygenType.__init__(self, version, compound)
@ -34,6 +33,7 @@ class DoxygenTypeSub(supermod.DoxygenType):
return results
supermod.DoxygenType.subclass = DoxygenTypeSub
# end class DoxygenTypeSub
@ -55,6 +55,7 @@ class CompoundTypeSub(supermod.CompoundType):
return results
supermod.CompoundType.subclass = CompoundTypeSub
# end class CompoundTypeSub
@ -64,6 +65,7 @@ class MemberTypeSub(supermod.MemberType):
def __init__(self, kind=None, refid=None, name=''):
supermod.MemberType.__init__(self, kind, refid, name)
supermod.MemberType.subclass = MemberTypeSub
# end class MemberTypeSub
@ -76,4 +78,3 @@ def parse(inFilename):
rootObj.build(rootNode)
return rootObj

Wyświetl plik

@ -4,16 +4,12 @@
# Generated Thu Jun 11 18:43:54 2009 by generateDS.py.
#
from __future__ import print_function
from __future__ import unicode_literals
import sys
from xml.dom import minidom
from xml.dom import Node
import six
#
# User methods
#
@ -28,12 +24,16 @@ except ImportError as exp:
class GeneratedsSuper(object):
def format_string(self, input_data, input_name=''):
return input_data
def format_integer(self, input_data, input_name=''):
return '%d' % input_data
def format_float(self, input_data, input_name=''):
return '%f' % input_data
def format_double(self, input_data, input_name=''):
return '%e' % input_data
def format_boolean(self, input_data, input_name=''):
return '%s' % input_data
@ -45,9 +45,9 @@ except ImportError as exp:
## from IPython.Shell import IPShellEmbed
## args = ''
## ipshell = IPShellEmbed(args,
# ipshell = IPShellEmbed(args,
## banner = 'Dropping into IPython',
## exit_msg = 'Leaving Interpreter, back to program.')
# exit_msg = 'Leaving Interpreter, back to program.')
# Then use the following line where and when you want to drop into the
# IPython shell:
@ -63,20 +63,23 @@ ExternalEncoding = 'ascii'
# Support/utility functions.
#
def showIndent(outfile, level):
for idx in range(level):
outfile.write(' ')
def quote_xml(inStr):
s1 = (isinstance(inStr, six.string_types) and inStr or
s1 = (isinstance(inStr, str) and inStr or
'%s' % inStr)
s1 = s1.replace('&', '&amp;')
s1 = s1.replace('<', '&lt;')
s1 = s1.replace('>', '&gt;')
return s1
def quote_attrib(inStr):
s1 = (isinstance(inStr, six.string_types) and inStr or
s1 = (isinstance(inStr, str) and inStr or
'%s' % inStr)
s1 = s1.replace('&', '&amp;')
s1 = s1.replace('<', '&lt;')
@ -90,6 +93,7 @@ def quote_attrib(inStr):
s1 = '"%s"' % s1
return s1
def quote_python(inStr):
s1 = inStr
if s1.find("'") == -1:
@ -121,26 +125,33 @@ class MixedContainer(object):
TypeDecimal = 5
TypeDouble = 6
TypeBoolean = 7
def __init__(self, category, content_type, name, value):
self.category = category
self.content_type = content_type
self.name = name
self.value = value
def getCategory(self):
return self.category
def getContenttype(self, content_type):
return self.content_type
def getValue(self):
return self.value
def getName(self):
return self.name
def export(self, outfile, level, name, namespace):
if self.category == MixedContainer.CategoryText:
outfile.write(self.value)
elif self.category == MixedContainer.CategorySimple:
self.exportSimple(outfile, level, name)
else: # category == MixedContainer.CategoryComplex
self.value.export(outfile, level, namespace,name)
self.value.export(outfile, level, namespace, name)
def exportSimple(self, outfile, level, name):
if self.content_type == MixedContainer.TypeString:
outfile.write('<%s>%s</%s>' % (self.name, self.value, self.name))
@ -152,19 +163,20 @@ class MixedContainer(object):
outfile.write('<%s>%f</%s>' % (self.name, self.value, self.name))
elif self.content_type == MixedContainer.TypeDouble:
outfile.write('<%s>%g</%s>' % (self.name, self.value, self.name))
def exportLiteral(self, outfile, level, name):
if self.category == MixedContainer.CategoryText:
showIndent(outfile, level)
outfile.write('MixedContainer(%d, %d, "%s", "%s"),\n' % \
(self.category, self.content_type, self.name, self.value))
outfile.write('MixedContainer(%d, %d, "%s", "%s"),\n' %
(self.category, self.content_type, self.name, self.value))
elif self.category == MixedContainer.CategorySimple:
showIndent(outfile, level)
outfile.write('MixedContainer(%d, %d, "%s", "%s"),\n' % \
(self.category, self.content_type, self.name, self.value))
outfile.write('MixedContainer(%d, %d, "%s", "%s"),\n' %
(self.category, self.content_type, self.name, self.value))
else: # category == MixedContainer.CategoryComplex
showIndent(outfile, level)
outfile.write('MixedContainer(%d, %d, "%s",\n' % \
(self.category, self.content_type, self.name,))
outfile.write('MixedContainer(%d, %d, "%s",\n' %
(self.category, self.content_type, self.name,))
self.value.exportLiteral(outfile, level + 1)
showIndent(outfile, level)
outfile.write(')\n')
@ -175,6 +187,7 @@ class _MemberSpec(object):
self.name = name
self.data_type = data_type
self.container = container
def set_name(self, name): self.name = name
def get_name(self): return self.name
def set_data_type(self, data_type): self.data_type = data_type
@ -190,12 +203,14 @@ class _MemberSpec(object):
class DoxygenType(GeneratedsSuper):
subclass = None
superclass = None
def __init__(self, version=None, compound=None):
self.version = version
if compound is None:
self.compound = []
else:
self.compound = compound
def factory(*args_, **kwargs_):
if DoxygenType.subclass:
return DoxygenType.subclass(*args_, **kwargs_)
@ -208,6 +223,7 @@ class DoxygenType(GeneratedsSuper):
def insert_compound(self, index, value): self.compound[index] = value
def get_version(self): return self.version
def set_version(self, version): self.version = version
def export(self, outfile, level, namespace_='', name_='DoxygenType', namespacedef_=''):
showIndent(outfile, level)
outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, ))
@ -219,27 +235,34 @@ class DoxygenType(GeneratedsSuper):
outfile.write('</%s%s>\n' % (namespace_, name_))
else:
outfile.write(' />\n')
def exportAttributes(self, outfile, level, namespace_='', name_='DoxygenType'):
outfile.write(' version=%s' % (self.format_string(quote_attrib(self.version).encode(ExternalEncoding), input_name='version'), ))
outfile.write(' version=%s' % (self.format_string(quote_attrib(
self.version).encode(ExternalEncoding), input_name='version'), ))
def exportChildren(self, outfile, level, namespace_='', name_='DoxygenType'):
for compound_ in self.compound:
compound_.export(outfile, level, namespace_, name_='compound')
def hasContent_(self):
if (
self.compound is not None
):
):
return True
else:
return False
def exportLiteral(self, outfile, level, name_='DoxygenType'):
level += 1
self.exportLiteralAttributes(outfile, level, name_)
if self.hasContent_():
self.exportLiteralChildren(outfile, level, name_)
def exportLiteralAttributes(self, outfile, level, name_):
if self.version is not None:
showIndent(outfile, level)
outfile.write('version = %s,\n' % (self.version,))
def exportLiteralChildren(self, outfile, level, name_):
showIndent(outfile, level)
outfile.write('compound=[\n')
@ -253,18 +276,21 @@ class DoxygenType(GeneratedsSuper):
level -= 1
showIndent(outfile, level)
outfile.write('],\n')
def build(self, node_):
attrs = node_.attributes
self.buildAttributes(attrs)
for child_ in node_.childNodes:
nodeName_ = child_.nodeName.split(':')[-1]
self.buildChildren(child_, nodeName_)
def buildAttributes(self, attrs):
if attrs.get('version'):
self.version = attrs.get('version').value
def buildChildren(self, child_, nodeName_):
if child_.nodeType == Node.ELEMENT_NODE and \
nodeName_ == 'compound':
nodeName_ == 'compound':
obj_ = CompoundType.factory()
obj_.build(child_)
self.compound.append(obj_)
@ -274,6 +300,7 @@ class DoxygenType(GeneratedsSuper):
class CompoundType(GeneratedsSuper):
subclass = None
superclass = None
def __init__(self, kind=None, refid=None, name=None, member=None):
self.kind = kind
self.refid = refid
@ -282,6 +309,7 @@ class CompoundType(GeneratedsSuper):
self.member = []
else:
self.member = member
def factory(*args_, **kwargs_):
if CompoundType.subclass:
return CompoundType.subclass(*args_, **kwargs_)
@ -298,6 +326,7 @@ class CompoundType(GeneratedsSuper):
def set_kind(self, kind): self.kind = kind
def get_refid(self): return self.refid
def set_refid(self, refid): self.refid = refid
def export(self, outfile, level, namespace_='', name_='CompoundType', namespacedef_=''):
showIndent(outfile, level)
outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, ))
@ -309,28 +338,35 @@ class CompoundType(GeneratedsSuper):
outfile.write('</%s%s>\n' % (namespace_, name_))
else:
outfile.write(' />\n')
def exportAttributes(self, outfile, level, namespace_='', name_='CompoundType'):
outfile.write(' kind=%s' % (quote_attrib(self.kind), ))
outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), ))
outfile.write(' refid=%s' % (self.format_string(quote_attrib(
self.refid).encode(ExternalEncoding), input_name='refid'), ))
def exportChildren(self, outfile, level, namespace_='', name_='CompoundType'):
if self.name is not None:
showIndent(outfile, level)
outfile.write('<%sname>%s</%sname>\n' % (namespace_, self.format_string(quote_xml(self.name).encode(ExternalEncoding), input_name='name'), namespace_))
outfile.write('<%sname>%s</%sname>\n' % (namespace_, self.format_string(
quote_xml(self.name).encode(ExternalEncoding), input_name='name'), namespace_))
for member_ in self.member:
member_.export(outfile, level, namespace_, name_='member')
def hasContent_(self):
if (
self.name is not None or
self.member is not None
):
):
return True
else:
return False
def exportLiteral(self, outfile, level, name_='CompoundType'):
level += 1
self.exportLiteralAttributes(outfile, level, name_)
if self.hasContent_():
self.exportLiteralChildren(outfile, level, name_)
def exportLiteralAttributes(self, outfile, level, name_):
if self.kind is not None:
showIndent(outfile, level)
@ -338,9 +374,11 @@ class CompoundType(GeneratedsSuper):
if self.refid is not None:
showIndent(outfile, level)
outfile.write('refid = %s,\n' % (self.refid,))
def exportLiteralChildren(self, outfile, level, name_):
showIndent(outfile, level)
outfile.write('name=%s,\n' % quote_python(self.name).encode(ExternalEncoding))
outfile.write('name=%s,\n' % quote_python(
self.name).encode(ExternalEncoding))
showIndent(outfile, level)
outfile.write('member=[\n')
level += 1
@ -353,26 +391,29 @@ class CompoundType(GeneratedsSuper):
level -= 1
showIndent(outfile, level)
outfile.write('],\n')
def build(self, node_):
attrs = node_.attributes
self.buildAttributes(attrs)
for child_ in node_.childNodes:
nodeName_ = child_.nodeName.split(':')[-1]
self.buildChildren(child_, nodeName_)
def buildAttributes(self, attrs):
if attrs.get('kind'):
self.kind = attrs.get('kind').value
if attrs.get('refid'):
self.refid = attrs.get('refid').value
def buildChildren(self, child_, nodeName_):
if child_.nodeType == Node.ELEMENT_NODE and \
nodeName_ == 'name':
nodeName_ == 'name':
name_ = ''
for text__content_ in child_.childNodes:
name_ += text__content_.nodeValue
self.name = name_
elif child_.nodeType == Node.ELEMENT_NODE and \
nodeName_ == 'member':
nodeName_ == 'member':
obj_ = MemberType.factory()
obj_.build(child_)
self.member.append(obj_)
@ -382,10 +423,12 @@ class CompoundType(GeneratedsSuper):
class MemberType(GeneratedsSuper):
subclass = None
superclass = None
def __init__(self, kind=None, refid=None, name=None):
self.kind = kind
self.refid = refid
self.name = name
def factory(*args_, **kwargs_):
if MemberType.subclass:
return MemberType.subclass(*args_, **kwargs_)
@ -398,6 +441,7 @@ class MemberType(GeneratedsSuper):
def set_kind(self, kind): self.kind = kind
def get_refid(self): return self.refid
def set_refid(self, refid): self.refid = refid
def export(self, outfile, level, namespace_='', name_='MemberType', namespacedef_=''):
showIndent(outfile, level)
outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, ))
@ -409,25 +453,32 @@ class MemberType(GeneratedsSuper):
outfile.write('</%s%s>\n' % (namespace_, name_))
else:
outfile.write(' />\n')
def exportAttributes(self, outfile, level, namespace_='', name_='MemberType'):
outfile.write(' kind=%s' % (quote_attrib(self.kind), ))
outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), ))
outfile.write(' refid=%s' % (self.format_string(quote_attrib(
self.refid).encode(ExternalEncoding), input_name='refid'), ))
def exportChildren(self, outfile, level, namespace_='', name_='MemberType'):
if self.name is not None:
showIndent(outfile, level)
outfile.write('<%sname>%s</%sname>\n' % (namespace_, self.format_string(quote_xml(self.name).encode(ExternalEncoding), input_name='name'), namespace_))
outfile.write('<%sname>%s</%sname>\n' % (namespace_, self.format_string(
quote_xml(self.name).encode(ExternalEncoding), input_name='name'), namespace_))
def hasContent_(self):
if (
self.name is not None
):
):
return True
else:
return False
def exportLiteral(self, outfile, level, name_='MemberType'):
level += 1
self.exportLiteralAttributes(outfile, level, name_)
if self.hasContent_():
self.exportLiteralChildren(outfile, level, name_)
def exportLiteralAttributes(self, outfile, level, name_):
if self.kind is not None:
showIndent(outfile, level)
@ -435,23 +486,28 @@ class MemberType(GeneratedsSuper):
if self.refid is not None:
showIndent(outfile, level)
outfile.write('refid = %s,\n' % (self.refid,))
def exportLiteralChildren(self, outfile, level, name_):
showIndent(outfile, level)
outfile.write('name=%s,\n' % quote_python(self.name).encode(ExternalEncoding))
outfile.write('name=%s,\n' % quote_python(
self.name).encode(ExternalEncoding))
def build(self, node_):
attrs = node_.attributes
self.buildAttributes(attrs)
for child_ in node_.childNodes:
nodeName_ = child_.nodeName.split(':')[-1]
self.buildChildren(child_, nodeName_)
def buildAttributes(self, attrs):
if attrs.get('kind'):
self.kind = attrs.get('kind').value
if attrs.get('refid'):
self.refid = attrs.get('refid').value
def buildChildren(self, child_, nodeName_):
if child_.nodeType == Node.ELEMENT_NODE and \
nodeName_ == 'name':
nodeName_ == 'name':
name_ = ''
for text__content_ in child_.childNodes:
name_ += text__content_.nodeValue
@ -465,6 +521,7 @@ Options:
-s Use the SAX parser, not the minidom parser.
"""
def usage():
print(USAGE_TEXT)
sys.exit(1)
@ -479,7 +536,7 @@ def parse(inFileName):
doc = None
sys.stdout.write('<?xml version="1.0" ?>\n')
rootObj.export(sys.stdout, 0, name_="doxygenindex",
namespacedef_='')
namespacedef_='')
return rootObj
@ -492,7 +549,7 @@ def parseString(inString):
doc = None
sys.stdout.write('<?xml version="1.0" ?>\n')
rootObj.export(sys.stdout, 0, name_="doxygenindex",
namespacedef_='')
namespacedef_='')
return rootObj
@ -518,9 +575,7 @@ def main():
usage()
if __name__ == '__main__':
main()
#import pdb
#pdb.run('main()')
# pdb.run('main()')

Wyświetl plik

@ -4,25 +4,13 @@
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-droneid
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
# SPDX-License-Identifier: GPL-3.0-or-later
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
"""
Utilities for extracting text from generated classes.
"""
from __future__ import unicode_literals
def is_string(txt):
if isinstance(txt, str):
@ -34,11 +22,13 @@ def is_string(txt):
pass
return False
def description(obj):
if obj is None:
return None
return description_bit(obj).strip()
def description_bit(obj):
if hasattr(obj, 'content'):
contents = [description_bit(item) for item in obj.content]
@ -51,7 +41,8 @@ def description_bit(obj):
elif is_string(obj):
return obj
else:
raise Exception('Expecting a string or something with content, content_ or value attribute')
raise Exception(
'Expecting a string or something with content, content_ or value attribute')
# If this bit is a paragraph then add one some line breaks.
if hasattr(obj, 'name') and obj.name == 'para':
result += "\n\n"

Wyświetl plik

@ -0,0 +1,446 @@
#!/usr/bin/env python
__applicationName__ = "doxypy"
__blurb__ = """
doxypy is an input filter for Doxygen. It preprocesses python
files so that docstrings of classes and functions are reformatted
into Doxygen-conform documentation blocks.
"""
__doc__ = __blurb__ + \
"""
In order to make Doxygen preprocess files through doxypy, simply
add the following lines to your Doxyfile:
FILTER_SOURCE_FILES = YES
INPUT_FILTER = "python /path/to/doxypy.py"
"""
__version__ = "0.4.2"
__date__ = "5th December 2008"
__website__ = "http://code.foosel.org/doxypy"
__author__ = (
"Philippe 'demod' Neumann (doxypy at demod dot org)",
"Gina 'foosel' Haeussge (gina at foosel dot net)"
)
__licenseName__ = "GPL v2"
__license__ = """This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import sys
import re
from argparse import ArgumentParser
class FSM(object):
"""Implements a finite state machine.
Transitions are given as 4-tuples, consisting of an origin state, a target
state, a condition for the transition (given as a reference to a function
which gets called with a given piece of input) and a pointer to a function
to be called upon the execution of the given transition.
"""
"""
@var transitions holds the transitions
@var current_state holds the current state
@var current_input holds the current input
@var current_transition hold the currently active transition
"""
def __init__(self, start_state=None, transitions=[]):
self.transitions = transitions
self.current_state = start_state
self.current_input = None
self.current_transition = None
def setStartState(self, state):
self.current_state = state
def addTransition(self, from_state, to_state, condition, callback):
self.transitions.append([from_state, to_state, condition, callback])
def makeTransition(self, input):
""" Makes a transition based on the given input.
@param input input to parse by the FSM
"""
for transition in self.transitions:
[from_state, to_state, condition, callback] = transition
if from_state == self.current_state:
match = condition(input)
if match:
self.current_state = to_state
self.current_input = input
self.current_transition = transition
if args.debug:
print("# FSM: executing (%s -> %s) for line '%s'" %
(from_state, to_state, input), file=sys.stderr)
callback(match)
return
class Doxypy(object):
def __init__(self):
string_prefixes = "[uU]?[rR]?"
self.start_single_comment_re = re.compile(
r"^\s*%s(''')" % string_prefixes)
self.end_single_comment_re = re.compile(r"(''')\s*$")
self.start_double_comment_re = re.compile(
r'^\s*%s(""")' % string_prefixes)
self.end_double_comment_re = re.compile(r'(""")\s*$')
self.single_comment_re = re.compile(
r"^\s*%s(''').*(''')\s*$" % string_prefixes)
self.double_comment_re = re.compile(
r'^\s*%s(""").*(""")\s*$' % string_prefixes)
self.defclass_re = re.compile(r"^(\s*)(def .+:|class .+:)")
self.empty_re = re.compile(r"^\s*$")
self.hashline_re = re.compile(r"^\s*#.*$")
self.importline_re = re.compile(r"^\s*(import |from .+ import)")
self.multiline_defclass_start_re = re.compile(
r"^(\s*)(def|class)(\s.*)?$")
self.multiline_defclass_end_re = re.compile(r":\s*$")
# Transition list format
# ["FROM", "TO", condition, action]
transitions = [
# FILEHEAD
# single line comments
["FILEHEAD", "FILEHEAD", self.single_comment_re.search,
self.appendCommentLine],
["FILEHEAD", "FILEHEAD", self.double_comment_re.search,
self.appendCommentLine],
# multiline comments
["FILEHEAD", "FILEHEAD_COMMENT_SINGLE",
self.start_single_comment_re.search, self.appendCommentLine],
["FILEHEAD_COMMENT_SINGLE", "FILEHEAD",
self.end_single_comment_re.search, self.appendCommentLine],
["FILEHEAD_COMMENT_SINGLE", "FILEHEAD_COMMENT_SINGLE",
self.catchall, self.appendCommentLine],
["FILEHEAD", "FILEHEAD_COMMENT_DOUBLE",
self.start_double_comment_re.search, self.appendCommentLine],
["FILEHEAD_COMMENT_DOUBLE", "FILEHEAD",
self.end_double_comment_re.search, self.appendCommentLine],
["FILEHEAD_COMMENT_DOUBLE", "FILEHEAD_COMMENT_DOUBLE",
self.catchall, self.appendCommentLine],
# other lines
["FILEHEAD", "FILEHEAD", self.empty_re.search, self.appendFileheadLine],
["FILEHEAD", "FILEHEAD", self.hashline_re.search, self.appendFileheadLine],
["FILEHEAD", "FILEHEAD", self.importline_re.search,
self.appendFileheadLine],
["FILEHEAD", "DEFCLASS", self.defclass_re.search, self.resetCommentSearch],
["FILEHEAD", "DEFCLASS_MULTI",
self.multiline_defclass_start_re.search, self.resetCommentSearch],
["FILEHEAD", "DEFCLASS_BODY", self.catchall, self.appendFileheadLine],
# DEFCLASS
# single line comments
["DEFCLASS", "DEFCLASS_BODY",
self.single_comment_re.search, self.appendCommentLine],
["DEFCLASS", "DEFCLASS_BODY",
self.double_comment_re.search, self.appendCommentLine],
# multiline comments
["DEFCLASS", "COMMENT_SINGLE",
self.start_single_comment_re.search, self.appendCommentLine],
["COMMENT_SINGLE", "DEFCLASS_BODY",
self.end_single_comment_re.search, self.appendCommentLine],
["COMMENT_SINGLE", "COMMENT_SINGLE",
self.catchall, self.appendCommentLine],
["DEFCLASS", "COMMENT_DOUBLE",
self.start_double_comment_re.search, self.appendCommentLine],
["COMMENT_DOUBLE", "DEFCLASS_BODY",
self.end_double_comment_re.search, self.appendCommentLine],
["COMMENT_DOUBLE", "COMMENT_DOUBLE",
self.catchall, self.appendCommentLine],
# other lines
["DEFCLASS", "DEFCLASS", self.empty_re.search, self.appendDefclassLine],
["DEFCLASS", "DEFCLASS", self.defclass_re.search, self.resetCommentSearch],
["DEFCLASS", "DEFCLASS_MULTI",
self.multiline_defclass_start_re.search, self.resetCommentSearch],
["DEFCLASS", "DEFCLASS_BODY", self.catchall, self.stopCommentSearch],
# DEFCLASS_BODY
["DEFCLASS_BODY", "DEFCLASS",
self.defclass_re.search, self.startCommentSearch],
["DEFCLASS_BODY", "DEFCLASS_MULTI",
self.multiline_defclass_start_re.search, self.startCommentSearch],
["DEFCLASS_BODY", "DEFCLASS_BODY", self.catchall, self.appendNormalLine],
# DEFCLASS_MULTI
["DEFCLASS_MULTI", "DEFCLASS",
self.multiline_defclass_end_re.search, self.appendDefclassLine],
["DEFCLASS_MULTI", "DEFCLASS_MULTI",
self.catchall, self.appendDefclassLine],
]
self.fsm = FSM("FILEHEAD", transitions)
self.outstream = sys.stdout
self.output = []
self.comment = []
self.filehead = []
self.defclass = []
self.indent = ""
def __closeComment(self):
"""Appends any open comment block and triggering block to the output."""
if args.autobrief:
if len(self.comment) == 1 \
or (len(self.comment) > 2 and self.comment[1].strip() == ''):
self.comment[0] = self.__docstringSummaryToBrief(
self.comment[0])
if self.comment:
block = self.makeCommentBlock()
self.output.extend(block)
if self.defclass:
self.output.extend(self.defclass)
def __docstringSummaryToBrief(self, line):
"""Adds \\brief to the docstrings summary line.
A \\brief is prepended, provided no other doxygen command is at the
start of the line.
"""
stripped = line.strip()
if stripped and not stripped[0] in ('@', '\\'):
return "\\brief " + line
else:
return line
def __flushBuffer(self):
"""Flushes the current outputbuffer to the outstream."""
if self.output:
try:
if args.debug:
print("# OUTPUT: ", self.output, file=sys.stderr)
print("\n".join(self.output), file=self.outstream)
self.outstream.flush()
except IOError:
# Fix for FS#33. Catches "broken pipe" when doxygen closes
# stdout prematurely upon usage of INPUT_FILTER, INLINE_SOURCES
# and FILTER_SOURCE_FILES.
pass
self.output = []
def catchall(self, input):
"""The catchall-condition, always returns true."""
return True
def resetCommentSearch(self, match):
"""Restarts a new comment search for a different triggering line.
Closes the current commentblock and starts a new comment search.
"""
if args.debug:
print("# CALLBACK: resetCommentSearch", file=sys.stderr)
self.__closeComment()
self.startCommentSearch(match)
def startCommentSearch(self, match):
"""Starts a new comment search.
Saves the triggering line, resets the current comment and saves
the current indentation.
"""
if args.debug:
print("# CALLBACK: startCommentSearch", file=sys.stderr)
self.defclass = [self.fsm.current_input]
self.comment = []
self.indent = match.group(1)
def stopCommentSearch(self, match):
"""Stops a comment search.
Closes the current commentblock, resets the triggering line and
appends the current line to the output.
"""
if args.debug:
print("# CALLBACK: stopCommentSearch", file=sys.stderr)
self.__closeComment()
self.defclass = []
self.output.append(self.fsm.current_input)
def appendFileheadLine(self, match):
"""Appends a line in the FILEHEAD state.
Closes the open comment block, resets it and appends the current line.
"""
if args.debug:
print("# CALLBACK: appendFileheadLine", file=sys.stderr)
self.__closeComment()
self.comment = []
self.output.append(self.fsm.current_input)
def appendCommentLine(self, match):
"""Appends a comment line.
The comment delimiter is removed from multiline start and ends as
well as singleline comments.
"""
if args.debug:
print("# CALLBACK: appendCommentLine", file=sys.stderr)
(from_state, to_state, condition, callback) = self.fsm.current_transition
# single line comment
if (from_state == "DEFCLASS" and to_state == "DEFCLASS_BODY") \
or (from_state == "FILEHEAD" and to_state == "FILEHEAD"):
# remove comment delimiter from begin and end of the line
activeCommentDelim = match.group(1)
line = self.fsm.current_input
self.comment.append(line[line.find(
activeCommentDelim) + len(activeCommentDelim):line.rfind(activeCommentDelim)])
if (to_state == "DEFCLASS_BODY"):
self.__closeComment()
self.defclass = []
# multiline start
elif from_state == "DEFCLASS" or from_state == "FILEHEAD":
# remove comment delimiter from begin of the line
activeCommentDelim = match.group(1)
line = self.fsm.current_input
self.comment.append(
line[line.find(activeCommentDelim) + len(activeCommentDelim):])
# multiline end
elif to_state == "DEFCLASS_BODY" or to_state == "FILEHEAD":
# remove comment delimiter from end of the line
activeCommentDelim = match.group(1)
line = self.fsm.current_input
self.comment.append(line[0:line.rfind(activeCommentDelim)])
if (to_state == "DEFCLASS_BODY"):
self.__closeComment()
self.defclass = []
# in multiline comment
else:
# just append the comment line
self.comment.append(self.fsm.current_input)
def appendNormalLine(self, match):
"""Appends a line to the output."""
if args.debug:
print("# CALLBACK: appendNormalLine", file=sys.stderr)
self.output.append(self.fsm.current_input)
def appendDefclassLine(self, match):
"""Appends a line to the triggering block."""
if args.debug:
print("# CALLBACK: appendDefclassLine", file=sys.stderr)
self.defclass.append(self.fsm.current_input)
def makeCommentBlock(self):
"""Indents the current comment block with respect to the current
indentation level.
@returns a list of indented comment lines
"""
doxyStart = "##"
commentLines = self.comment
commentLines = ["%s# %s" % (self.indent, x) for x in commentLines]
l = [self.indent + doxyStart]
l.extend(commentLines)
return l
def parse(self, input):
"""Parses a python file given as input string and returns the doxygen-
compatible representation.
@param input the python code to parse
@returns the modified python code
"""
lines = input.split("\n")
for line in lines:
self.fsm.makeTransition(line)
if self.fsm.current_state == "DEFCLASS":
self.__closeComment()
return "\n".join(self.output)
def parseFile(self, filename):
"""Parses a python file given as input string and returns the doxygen-
compatible representation.
@param input the python code to parse
@returns the modified python code
"""
f = open(filename, 'r')
for line in f:
self.parseLine(line.rstrip('\r\n'))
if self.fsm.current_state == "DEFCLASS":
self.__closeComment()
self.__flushBuffer()
f.close()
def parseLine(self, line):
"""Parse one line of python and flush the resulting output to the
outstream.
@param line the python code line to parse
"""
self.fsm.makeTransition(line)
self.__flushBuffer()
def argParse():
"""Parses commandline args."""
parser = ArgumentParser(prog=__applicationName__)
parser.add_argument("--version", action="version",
version="%(prog)s " + __version__
)
parser.add_argument("--autobrief", action="store_true",
help="use the docstring summary line as \\brief description"
)
parser.add_argument("--debug", action="store_true",
help="enable debug output on stderr"
)
parser.add_argument("filename", metavar="FILENAME")
return parser.parse_args()
def main():
"""Starts the parser on the file given by the filename as the first
argument on the commandline.
"""
global args
args = argParse()
fsm = Doxypy()
fsm.parseFile(args.filename)
if __name__ == "__main__":
main()

Wyświetl plik

@ -4,4 +4,3 @@
* module are listed here or in the subcategories below.
*
*/

Wyświetl plik

@ -0,0 +1,19 @@
#ifndef PYDOC_MACROS_H
#define PYDOC_MACROS_H
#define __EXPAND(x) x
#define __COUNT(_1, _2, _3, _4, _5, _6, _7, COUNT, ...) COUNT
#define __VA_SIZE(...) __EXPAND(__COUNT(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1))
#define __CAT1(a, b) a##b
#define __CAT2(a, b) __CAT1(a, b)
#define __DOC1(n1) __doc_##n1
#define __DOC2(n1, n2) __doc_##n1##_##n2
#define __DOC3(n1, n2, n3) __doc_##n1##_##n2##_##n3
#define __DOC4(n1, n2, n3, n4) __doc_##n1##_##n2##_##n3##_##n4
#define __DOC5(n1, n2, n3, n4, n5) __doc_##n1##_##n2##_##n3##_##n4##_##n5
#define __DOC6(n1, n2, n3, n4, n5, n6) __doc_##n1##_##n2##_##n3##_##n4##_##n5##_##n6
#define __DOC7(n1, n2, n3, n4, n5, n6, n7) \
__doc_##n1##_##n2##_##n3##_##n4##_##n5##_##n6##_##n7
#define DOC(...) __EXPAND(__EXPAND(__CAT2(__DOC, __VA_SIZE(__VA_ARGS__)))(__VA_ARGS__))
#endif // PYDOC_MACROS_H

Wyświetl plik

@ -2,42 +2,37 @@
# Copyright 2010-2012 Free Software Foundation, Inc.
#
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-droneid
# This file is a part of gnuradio
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
# SPDX-License-Identifier: GPL-3.0-or-later
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
"""
Creates the swig_doc.i SWIG interface file.
Execute using: python swig_doc.py xml_path outputfilename
Updates the *pydoc_h files for a module
Execute using: python update_pydoc.py xml_path outputfilename
The file instructs SWIG to transfer the doxygen comments into the
The file instructs Pybind11 to transfer the doxygen comments into the
python docstrings.
"""
from __future__ import unicode_literals
import sys, time
import os
import sys
import time
import glob
import re
import json
from argparse import ArgumentParser
from doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile
from doxyxml import DoxyOther, base
def py_name(name):
bits = name.split('_')
return '_'.join(bits[1:])
def make_name(name):
bits = name.split('_')
return bits[0] + '_make_' + '_'.join(bits[1:])
@ -62,6 +57,7 @@ class Block(object):
is_a_block = di.has_member(friendname, DoxyFunction)
return is_a_block
class Block2(object):
"""
Checks if doxyxml produced objects correspond to a new style
@ -75,7 +71,8 @@ class Block2(object):
# Check for a parsing error.
if item.error():
return False
is_a_block2 = item.has_member('make', DoxyFunction) and item.has_member('sptr', DoxyOther)
is_a_block2 = item.has_member(
'make', DoxyFunction) and item.has_member('sptr', DoxyOther)
return is_a_block2
@ -87,6 +84,7 @@ def utoascii(text):
return ''
out = text.encode('ascii', 'replace')
# swig will require us to replace blackslash with 4 backslashes
# TODO: evaluate what this should be for pybind11
out = out.replace(b'\\', b'\\\\\\\\')
out = out.replace(b'"', b'\\"').decode('ascii')
return str(out)
@ -105,6 +103,7 @@ def combine_descriptions(obj):
description.append(dd)
return utoascii('\n\n'.join(description)).strip()
def format_params(parameteritems):
output = ['Args:']
template = ' {0} : {1}'
@ -112,10 +111,13 @@ def format_params(parameteritems):
output.append(template.format(pi.name, pi.description))
return '\n'.join(output)
entry_templ = '%feature("docstring") {name} "{docstring}"'
def make_entry(obj, name=None, templ="{description}", description=None, params=[]):
"""
Create a docstring entry for a swig interface file.
Create a docstring key/value pair, where the key is the object name.
obj - a doxyxml object from which documentation will be extracted.
name - the name of the C object (defaults to obj.name())
@ -125,7 +127,9 @@ def make_entry(obj, name=None, templ="{description}", description=None, params=[
used as the description instead of extracting it from obj.
"""
if name is None:
name=obj.name()
name = obj.name()
if hasattr(obj, '_parse_data') and hasattr(obj._parse_data, 'definition'):
name = obj._parse_data.definition.split(' ')[-1]
if "operator " in name:
return ''
if description is None:
@ -134,56 +138,28 @@ def make_entry(obj, name=None, templ="{description}", description=None, params=[
description += '\n\n'
description += utoascii(format_params(params))
docstring = templ.format(description=description)
if not docstring:
return ''
return entry_templ.format(
name=name,
docstring=docstring,
)
def make_func_entry(func, name=None, description=None, params=None):
"""
Create a function docstring entry for a swig interface file.
func - a doxyxml object from which documentation will be extracted.
name - the name of the C object (defaults to func.name())
description - if this optional variable is set then it's value is
used as the description instead of extracting it from func.
params - a parameter list that overrides using func.params.
"""
#if params is None:
# params = func.params
#params = [prm.declname for prm in params]
#if params:
# sig = "Params: (%s)" % ", ".join(params)
#else:
# sig = "Params: (NONE)"
#templ = "{description}\n\n" + sig
#return make_entry(func, name=name, templ=utoascii(templ),
# description=description)
return make_entry(func, name=name, description=description, params=params)
return {name: docstring}
def make_class_entry(klass, description=None, ignored_methods=[], params=None):
"""
Create a class docstring for a swig interface file.
Create a class docstring key/value pair.
"""
if params is None:
params = klass.params
output = []
output.append(make_entry(klass, description=description, params=params))
output = {}
output.update(make_entry(klass, description=description, params=params))
for func in klass.in_category(DoxyFunction):
if func.name() not in ignored_methods:
name = klass.name() + '::' + func.name()
output.append(make_func_entry(func, name=name))
return "\n\n".join(output)
output.update(make_entry(func, name=name))
return output
def make_block_entry(di, block):
"""
Create class and function docstrings of a gnuradio block for a
swig interface file.
Create class and function docstrings of a gnuradio block
"""
descriptions = []
# Get the documentation associated with the class.
@ -208,48 +184,42 @@ def make_block_entry(di, block):
super_description = "\n\n".join(descriptions)
# Associate the combined description with the class and
# the make function.
output = []
output.append(make_class_entry(block, description=super_description))
output.append(make_func_entry(make_func, description=super_description,
params=block.params))
return "\n\n".join(output)
output = {}
output.update(make_class_entry(block, description=super_description))
output.update(make_entry(make_func, description=super_description,
params=block.params))
return output
def make_block2_entry(di, block):
"""
Create class and function docstrings of a new style gnuradio block for a
swig interface file.
Create class and function docstrings of a new style gnuradio block
"""
descriptions = []
# For new style blocks all the relevant documentation should be
# associated with the 'make' method.
class_description = combine_descriptions(block)
make_func = block.get_member('make', DoxyFunction)
make_description = combine_descriptions(make_func)
description = class_description + "\n\nConstructor Specific Documentation:\n\n" + make_description
description = class_description + \
"\n\nConstructor Specific Documentation:\n\n" + make_description
# Associate the combined description with the class and
# the make function.
output = []
output.append(make_class_entry(
block, description=description,
ignored_methods=['make'], params=make_func.params))
output = {}
output.update(make_class_entry(
block, description=description,
ignored_methods=['make'], params=make_func.params))
makename = block.name() + '::make'
output.append(make_func_entry(
make_func, name=makename, description=description,
params=make_func.params))
return "\n\n".join(output)
output.update(make_entry(
make_func, name=makename, description=description,
params=make_func.params))
return output
def make_swig_interface_file(di, swigdocfilename, custom_output=None):
output = ["""
/*
* This file was automatically generated using swig_doc.py.
*
* Any changes to it will be lost next time it is regenerated.
*/
"""]
def get_docstrings_dict(di, custom_output=None):
if custom_output is not None:
output.append(custom_output)
output = {}
if custom_output:
output.update(custom_output)
# Create docstrings for the blocks.
blocks = di.in_category(Block)
@ -262,21 +232,23 @@ def make_swig_interface_file(di, swigdocfilename, custom_output=None):
# Don't want to risk writing to output twice.
if make_func.name() not in make_funcs:
make_funcs.add(make_func.name())
output.append(make_block_entry(di, block))
output.update(make_block_entry(di, block))
except block.ParsingError:
sys.stderr.write('Parsing error for block {0}\n'.format(block.name()))
sys.stderr.write(
'Parsing error for block {0}\n'.format(block.name()))
raise
for block in blocks2:
try:
make_func = block.get_member('make', DoxyFunction)
make_func_name = block.name() +'::make'
make_func_name = block.name() + '::make'
# Don't want to risk writing to output twice.
if make_func_name not in make_funcs:
make_funcs.add(make_func_name)
output.append(make_block2_entry(di, block))
output.update(make_block2_entry(di, block))
except block.ParsingError:
sys.stderr.write('Parsing error for block {0}\n'.format(block.name()))
sys.stderr.write(
'Parsing error for block {0}\n'.format(block.name()))
raise
# Create docstrings for functions
@ -285,9 +257,10 @@ def make_swig_interface_file(di, swigdocfilename, custom_output=None):
if f.name() not in make_funcs and not f.name().startswith('std::')]
for f in funcs:
try:
output.append(make_func_entry(f))
output.update(make_entry(f))
except f.ParsingError:
sys.stderr.write('Parsing error for function {0}\n'.format(f.name()))
sys.stderr.write(
'Parsing error for function {0}\n'.format(f.name()))
# Create docstrings for classes
block_names = [block.name() for block in blocks]
@ -296,37 +269,104 @@ def make_swig_interface_file(di, swigdocfilename, custom_output=None):
if k.name() not in block_names and not k.name().startswith('std::')]
for k in klasses:
try:
output.append(make_class_entry(k))
output.update(make_class_entry(k))
except k.ParsingError:
sys.stderr.write('Parsing error for class {0}\n'.format(k.name()))
# Docstrings are not created for anything that is not a function or a class.
# If this excludes anything important please add it here.
output = "\n\n".join(output)
return output
def sub_docstring_in_pydoc_h(pydoc_files, docstrings_dict, output_dir, filter_str=None):
if filter_str:
docstrings_dict = {
k: v for k, v in docstrings_dict.items() if k.startswith(filter_str)}
with open(os.path.join(output_dir, 'docstring_status'), 'w') as status_file:
for pydoc_file in pydoc_files:
if filter_str:
filter_str2 = "::".join((filter_str, os.path.split(
pydoc_file)[-1].split('_pydoc_template.h')[0]))
docstrings_dict2 = {
k: v for k, v in docstrings_dict.items() if k.startswith(filter_str2)}
else:
docstrings_dict2 = docstrings_dict
file_in = open(pydoc_file, 'r').read()
for key, value in docstrings_dict2.items():
file_in_tmp = file_in
try:
doc_key = key.split("::")
# if 'gr' in doc_key:
# doc_key.remove('gr')
doc_key = '_'.join(doc_key)
regexp = r'(__doc_{} =\sR\"doc\()[^)]*(\)doc\")'.format(
doc_key)
regexp = re.compile(regexp, re.MULTILINE)
(file_in, nsubs) = regexp.subn(
r'\1' + value + r'\2', file_in, count=1)
if nsubs == 1:
status_file.write("PASS: " + pydoc_file + "\n")
except KeyboardInterrupt:
raise KeyboardInterrupt
except: # be permissive, TODO log, but just leave the docstring blank
status_file.write("FAIL: " + pydoc_file + "\n")
file_in = file_in_tmp
output_pathname = os.path.join(output_dir, os.path.basename(
pydoc_file).replace('_template.h', '.h'))
with open(output_pathname, 'w') as file_out:
file_out.write(file_in)
def copy_docstring_templates(pydoc_files, output_dir):
with open(os.path.join(output_dir, 'docstring_status'), 'w') as status_file:
for pydoc_file in pydoc_files:
file_in = open(pydoc_file, 'r').read()
output_pathname = os.path.join(output_dir, os.path.basename(
pydoc_file).replace('_template.h', '.h'))
with open(output_pathname, 'w') as file_out:
file_out.write(file_in)
status_file.write("DONE")
def argParse():
"""Parses commandline args."""
desc = 'Scrape the doxygen generated xml for docstrings to insert into python bindings'
parser = ArgumentParser(description=desc)
parser.add_argument("function", help="Operation to perform on docstrings", choices=[
"scrape", "sub", "copy"])
parser.add_argument("--xml_path")
parser.add_argument("--bindings_dir")
parser.add_argument("--output_dir")
parser.add_argument("--json_path")
parser.add_argument("--filter", default=None)
return parser.parse_args()
swig_doc = open(swigdocfilename, 'w')
swig_doc.write(output)
swig_doc.close()
if __name__ == "__main__":
# Parse command line options and set up doxyxml.
err_msg = "Execute using: python swig_doc.py xml_path outputfilename"
if len(sys.argv) != 3:
raise Exception(err_msg)
xml_path = sys.argv[1]
swigdocfilename = sys.argv[2]
di = DoxyIndex(xml_path)
# gnuradio.gr.msq_queue.insert_tail and delete_head create errors unless docstrings are defined!
# This is presumably a bug in SWIG.
#msg_q = di.get_member(u'gr_msg_queue', DoxyClass)
#insert_tail = msg_q.get_member(u'insert_tail', DoxyFunction)
#delete_head = msg_q.get_member(u'delete_head', DoxyFunction)
output = []
#output.append(make_func_entry(insert_tail, name='gr_py_msg_queue__insert_tail'))
#output.append(make_func_entry(delete_head, name='gr_py_msg_queue__delete_head'))
custom_output = "\n\n".join(output)
# Generate the docstrings interface file.
make_swig_interface_file(di, swigdocfilename, custom_output=custom_output)
args = argParse()
if args.function.lower() == 'scrape':
di = DoxyIndex(args.xml_path)
docstrings_dict = get_docstrings_dict(di)
with open(args.json_path, 'w') as fp:
json.dump(docstrings_dict, fp)
elif args.function.lower() == 'sub':
with open(args.json_path, 'r') as fp:
docstrings_dict = json.load(fp)
pydoc_files = glob.glob(os.path.join(
args.bindings_dir, '*_pydoc_template.h'))
sub_docstring_in_pydoc_h(
pydoc_files, docstrings_dict, args.output_dir, args.filter)
elif args.function.lower() == 'copy':
pydoc_files = glob.glob(os.path.join(
args.bindings_dir, '*_pydoc_template.h'))
copy_docstring_templates(pydoc_files, args.output_dir)

Wyświetl plik

@ -1,4 +1,3 @@
It is considered good practice to add examples in here to demonstrate the
functionality of your OOT module. Python scripts, GRC flow graphs or other
code can go here.

Wyświetl plik

@ -3,28 +3,9 @@
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-droneid
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
# SPDX-License-Identifier: GPL-3.0-or-later
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
install(FILES
droneid_extractor.block.yml
droneid_time_sync.block.yml
droneid_demodulation.block.yml
droneid_misc_utils.block.yml
droneid_lte_decode.block.yml
droneid_decode.block.yml
droneid_normalized_xcorr_estimate.block.yml
droneid_variance.block.yml DESTINATION share/gnuradio/grc/blocks
droneid_misc_utils.block.yml DESTINATION share/gnuradio/grc/blocks
)

Wyświetl plik

@ -1,38 +0,0 @@
id: droneid_decode
label: decode
category: '[droneid]'
templates:
imports: import droneid
make: droneid.decode(${debug_path})
# Make one 'parameters' list entry for every parameter you want settable from the GUI.
# Keys include:
# * id (makes the value accessible as \$keyname, e.g. in the make entry)
# * label (label shown in the GUI)
# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
parameters:
- id: debug_path
label: Debug Path
dtype: string
# Make one 'inputs' list entry per input and one 'outputs' list entry per output.
# Keys include:
# * label (an identifier for the GUI)
# * domain (optional - stream or message. Default is stream)
# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
# * vlen (optional - data stream vector length. Default is 1)
# * optional (optional - set to 1 for optional inputs. Default is 0)
inputs:
- label: pdus
domain: message
optional: 0
outputs:
- label: pdus
domain: message
optional: 1
# 'file_format' specifies the version of the GRC yml format used in the file
# and should usually not be changed.
file_format: 1

Wyświetl plik

@ -1,41 +0,0 @@
id: droneid_demodulation
label: demodulation
category: '[droneid]'
templates:
imports: import droneid
make: droneid.demodulation(${sample_rate}, ${debug_path})
# Make one 'parameters' list entry for every parameter you want settable from the GUI.
# Keys include:
# * id (makes the value accessible as \$keyname, e.g. in the make entry)
# * label (label shown in the GUI)
# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
parameters:
- id: sample_rate
label: Sample Rate
dtype: float
- id: debug_path
label: Debug path
dtype: string
# Make one 'inputs' list entry per input and one 'outputs' list entry per output.
# Keys include:
# * label (an identifier for the GUI)
# * domain (optional - stream or message. Default is stream)
# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
# * vlen (optional - data stream vector length. Default is 1)
# * optional (optional - set to 1 for optional inputs. Default is 0)
inputs:
- label: pdus
domain: message
optional: 0
outputs:
- label: pdus
domain: message
optional: 1
# 'file_format' specifies the version of the GRC yml format used in the file
# and should usually not be changed.
file_format: 1

Wyświetl plik

@ -1,49 +0,0 @@
id: droneid_extractor
label: extractor
category: '[droneid]'
templates:
imports: import droneid
make: droneid.extractor(${sample_rate}, ${threshold})
callbacks:
- set_threshold(${threshold})
# Make one 'parameters' list entry for every parameter you want settable from the GUI.
# Keys include:
# * id (makes the value accessible as \$keyname, e.g. in the make entry)
# * label (label shown in the GUI)
# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
parameters:
- id: sample_rate
label: Sample Rate
dtype: float
- id: threshold
label: Correlator threshold
dtype: float
# Make one 'inputs' list entry per input and one 'outputs' list entry per output.
# Keys include:
# * label (an identifier for the GUI)
# * domain (optional - stream or message. Default is stream)
# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
# * vlen (optional - data stream vector length. Default is 1)
# * optional (optional - set to 1 for optional inputs. Default is 0)
inputs:
- label: samples
domain: stream
dtype: complex
vlen: 1
optional: 0
- label: corr
domain: stream
dtype: float
vlen: 1
optional: 0
outputs:
- label: pdus
domain: message
optional: true
# 'file_format' specifies the version of the GRC yml format used in the file
# and should usually not be changed.
file_format: 1

Wyświetl plik

@ -1,45 +0,0 @@
id: droneid_lte_decode
label: lte_decode
category: '[droneid]'
templates:
imports: import droneid
make: droneid.lte_decode()
# Make one 'parameters' list entry for every parameter you want settable from the GUI.
# Keys include:
# * id (makes the value accessible as \$keyname, e.g. in the make entry)
# * label (label shown in the GUI)
# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
parameters:
- id: ...
label: ...
dtype: ...
- id: ...
label: ...
dtype: ...
# Make one 'inputs' list entry per input and one 'outputs' list entry per output.
# Keys include:
# * label (an identifier for the GUI)
# * domain (optional - stream or message. Default is stream)
# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
# * vlen (optional - data stream vector length. Default is 1)
# * optional (optional - set to 1 for optional inputs. Default is 0)
inputs:
- label: ...
domain: ...
dtype: ...
vlen: ...
optional: ...
outputs:
- label: ...
domain: ...
dtype: ...
vlen: ...
optional: ...
# 'file_format' specifies the version of the GRC yml format used in the file
# and should usually not be changed.
file_format: 1

Wyświetl plik

@ -3,15 +3,23 @@ label: misc_utils
category: '[droneid]'
templates:
imports: import droneid
imports: from gnuradio import droneid
make: droneid.misc_utils()
# Make one 'parameters' list entry for every parameter you want settable from the GUI.
# Keys include:
# * id (makes the value accessible as \$keyname, e.g. in the make entry)
# * id (makes the value accessible as keyname, e.g. in the make entry)
# * label (label shown in the GUI)
# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
# * default
parameters:
- id: parametername_replace_me
label: FIX ME:
dtype: string
default: You need to fill in your grc/droneid_misc_utils.block.yaml
#- id: ...
# label: ...
# dtype: ...
# Make one 'inputs' list entry per input and one 'outputs' list entry per output.
# Keys include:
@ -21,8 +29,18 @@ parameters:
# * vlen (optional - data stream vector length. Default is 1)
# * optional (optional - set to 1 for optional inputs. Default is 0)
inputs:
#- label: ...
# domain: ...
# dtype: ...
# vlen: ...
# optional: ...
outputs:
#- label: ...
# domain: ...
# dtype: ...
# vlen: ...
# optional: ...
# 'file_format' specifies the version of the GRC yml format used in the file
# and should usually not be changed.

Wyświetl plik

@ -1,42 +0,0 @@
id: droneid_normalized_xcorr_estimate
label: normalized_xcorr_estimate
category: '[droneid]'
templates:
imports: import droneid
make: droneid.normalized_xcorr_estimate(${taps})
# Make one 'parameters' list entry for every parameter you want settable from the GUI.
# Keys include:
# * id (makes the value accessible as \$keyname, e.g. in the make entry)
# * label (label shown in the GUI)
# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
parameters:
- id: taps
label: Filter Taps
dtype: complex_vector
# Make one 'inputs' list entry per input and one 'outputs' list entry per output.
# Keys include:
# * label (an identifier for the GUI)
# * domain (optional - stream or message. Default is stream)
# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
# * vlen (optional - data stream vector length. Default is 1)
# * optional (optional - set to 1 for optional inputs. Default is 0)
inputs:
- label: in
domain: stream
dtype: complex
vlen: 1
optional: 0
outputs:
- label: out
domain: stream
dtype: complex
vlen: 1
optional: 0
# 'file_format' specifies the version of the GRC yml format used in the file
# and should usually not be changed.
file_format: 1

Wyświetl plik

@ -1,42 +0,0 @@
id: droneid_time_sync
label: time_sync
category: '[droneid]'
templates:
imports: import droneid
make: droneid.time_sync(${sample_rate}, ${debug_path})
# Make one 'parameters' list entry for every parameter you want settable from the GUI.
# Keys include:
# * id (makes the value accessible as \$keyname, e.g. in the make entry)
# * label (label shown in the GUI)
# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
parameters:
- id: sample_rate
label: Sample Rate
dtype: float
- id: debug_path
label: Debug Path
dtype: string
# Make one 'inputs' list entry per input and one 'outputs' list entry per output.
# Keys include:
# * label (an identifier for the GUI)
# * domain (optional - stream or message. Default is stream)
# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
# * vlen (optional - data stream vector length. Default is 1)
# * optional (optional - set to 1 for optional inputs. Default is 0)
inputs:
- label: pdus
domain: message
optional: 0
outputs:
- label: pdus
domain: message
optional: 1
# 'file_format' specifies the version of the GRC yml format used in the file
# and should usually not be changed.
file_format: 1

Wyświetl plik

@ -1,42 +0,0 @@
id: droneid_variance
label: variance
category: '[droneid]'
templates:
imports: import droneid
make: droneid.variance(${window_size})
# Make one 'parameters' list entry for every parameter you want settable from the GUI.
# Keys include:
# * id (makes the value accessible as \$keyname, e.g. in the make entry)
# * label (label shown in the GUI)
# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
parameters:
- id: window_size
label: Window Size
dtype: int
# Make one 'inputs' list entry per input and one 'outputs' list entry per output.
# Keys include:
# * label (an identifier for the GUI)
# * domain (optional - stream or message. Default is stream)
# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
# * vlen (optional - data stream vector length. Default is 1)
# * optional (optional - set to 1 for optional inputs. Default is 0)
inputs:
- label: in
domain: stream
dtype: complex
vlen: 1
optional: 0
outputs:
- label: out
domain: stream
dtype: float
vlen: 1
optional: 0
# 'file_format' specifies the version of the GRC yml format used in the file
# and should usually not be changed.
file_format: 1

Wyświetl plik

@ -1,36 +0,0 @@
# Copyright 2011,2012 Free Software Foundation, Inc.
#
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-droneid
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
########################################################################
# Install public header files
########################################################################
install(FILES
api.h
extractor.h
time_sync.h
../../lib/utils.h
demodulation.h
misc_utils.h
lte_decode.h
decode.h
normalized_xcorr.h
normalized_xcorr_estimate.h
variance.h DESTINATION include/droneid
)

Wyświetl plik

@ -1,34 +0,0 @@
/*
* Copyright 2011 Free Software Foundation, Inc.
*
* This file was generated by gr_modtool, a tool from the GNU Radio framework
* This file is a part of gr-droneid
*
* GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* GNU Radio is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Radio; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DRONEID_API_H
#define INCLUDED_DRONEID_API_H
#include <gnuradio/attributes.h>
#ifdef gnuradio_droneid_EXPORTS
#define DRONEID_API __GR_ATTR_EXPORT
#else
#define DRONEID_API __GR_ATTR_IMPORT
#endif
#endif /* INCLUDED_DRONEID_API_H */

Wyświetl plik

@ -1,55 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DRONEID_DECODE_H
#define INCLUDED_DRONEID_DECODE_H
#include <droneid/api.h>
#include <gnuradio/sync_block.h>
namespace gr {
namespace droneid {
/*!
* \brief <+description of block+>
* \ingroup droneid
*
*/
class DRONEID_API decode : virtual public gr::sync_block
{
public:
typedef boost::shared_ptr<decode> sptr;
/*!
* \brief Return a shared_ptr to a new instance of droneid::decode.
*
* To avoid accidental use of raw pointers, droneid::decode's
* constructor is in a private implementation
* class. droneid::decode::make is the public interface for
* creating new instances.
*/
static sptr make(const std::string & debug_path);
};
} // namespace droneid
} // namespace gr
#endif /* INCLUDED_DRONEID_DECODE_H */

Wyświetl plik

@ -1,55 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DRONEID_DEMODULATION_H
#define INCLUDED_DRONEID_DEMODULATION_H
#include <droneid/api.h>
#include <gnuradio/sync_block.h>
namespace gr {
namespace droneid {
/*!
* \brief <+description of block+>
* \ingroup droneid
*
*/
class DRONEID_API demodulation : virtual public gr::sync_block
{
public:
typedef boost::shared_ptr<demodulation> sptr;
/*!
* \brief Return a shared_ptr to a new instance of droneid::demodulation.
*
* To avoid accidental use of raw pointers, droneid::demodulation's
* constructor is in a private implementation
* class. droneid::demodulation::make is the public interface for
* creating new instances.
*/
static sptr make(double sample_rate, const std::string & debug_path);
};
} // namespace droneid
} // namespace gr
#endif /* INCLUDED_DRONEID_DEMODULATION_H */

Wyświetl plik

@ -1,57 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DRONEID_EXTRACTOR_H
#define INCLUDED_DRONEID_EXTRACTOR_H
#include <droneid/api.h>
#include <gnuradio/sync_block.h>
namespace gr {
namespace droneid {
/*!
* \brief <+description of block+>
* \ingroup droneid
*
*/
class DRONEID_API extractor : virtual public gr::sync_block
{
public:
typedef boost::shared_ptr<extractor> sptr;
/*!
* \brief Return a shared_ptr to a new instance of droneid::extractor.
*
* To avoid accidental use of raw pointers, droneid::extractor's
* constructor is in a private implementation
* class. droneid::extractor::make is the public interface for
* creating new instances.
*/
static sptr make(double /*sample_rate*/, float /*threshold*/);
virtual void set_threshold(float /*threshold*/) = 0;
};
} // namespace droneid
} // namespace gr
#endif /* INCLUDED_DRONEID_EXTRACTOR_H */

Wyświetl plik

@ -1,75 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DRONEID_LTE_DECODE_H
#define INCLUDED_DRONEID_LTE_DECODE_H
#include <droneid/api.h>
#include <vector>
#ifdef __cplusplus
extern "C" {
#endif
#include <turbofec/rate_match.h>
#include <turbofec/turbo.h>
#ifdef __cplusplus
}
#endif
// This line is required before the include of CRC.h so that it actually loads the CRC_24_LTEA definition
#define CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS
#include <CRC.h>
namespace gr {
namespace droneid {
/*!
* \brief <+description+>
*
*/
class DRONEID_API lte_decode {
protected:
static constexpr uint32_t TURBO_ITERATIONS = 4;
static constexpr uint32_t TURBO_DECODER_BIT_COUNT = 1412;
static constexpr uint32_t TURBO_DECODER_INPUT_BIT_COUNT = 7200;
static constexpr uint32_t EXPECTED_PAYLOAD_BYTES = 176;
static constexpr uint32_t EXPECTED_PAYLOAD_BITS = EXPECTED_PAYLOAD_BYTES * 8;
std::vector<int8_t> d1_, d2_, d3_;
std::vector<int8_t> turbo_decoder_input_;
std::vector<uint8_t> decoded_bytes_;
struct lte_rate_matcher * rate_matcher_ = nullptr;
struct tdecoder * turbo_decoder_ = nullptr;
struct lte_rate_matcher_io rate_matcher_io_;
public:
lte_decode();
~lte_decode();
std::vector<uint8_t> decode(const std::vector<int8_t> & bits);
};
} // namespace droneid
} // namespace gr
#endif /* INCLUDED_DRONEID_LTE_DECODE_H */

Wyświetl plik

@ -1,108 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DRONEID_MISC_UTILS_H
#define INCLUDED_DRONEID_MISC_UTILS_H
#include <droneid/api.h>
#include <vector>
#include <array>
#include <complex>
namespace gr {
namespace droneid {
/*!
* \brief <+description+>
*
*/
class DRONEID_API misc_utils {
public:
static constexpr double CARRIER_SPACING = 15e3;
static constexpr uint32_t OCCUPIED_CARRIERS_EXC_DC = 600;
static constexpr uint32_t OCCUPIED_CARRIERS_INC_DC = 601;
static uint32_t get_long_cp_len(double sample_rate);
static uint32_t get_short_cp_len(double sample_rate);
static uint32_t get_fft_size(double sample_rate);
static std::vector<std::complex<float>> create_gaussian_noise(uint32_t sample_count);
static std::vector<std::complex<float>> create_zc_sequence(double sample_rate, uint32_t root);
static std::vector<std::complex<float>> conj(const std::vector<std::complex<float>> & input);
static std::complex<float> mean(const std::vector<std::complex<float>> & samples);
static float var(const std::vector<std::complex<float>> & samples);
static float var_no_mean(const std::vector<std::complex<float>> & samples);
static std::complex<float> mean(const std::complex<float> * samples, uint32_t sample_count);
static float var(const std::complex<float> * samples, uint32_t sample_count);
static float var_no_mean(const std::complex<float> * samples, uint32_t sample_count);
static void write(const std::string & path, const void * element, uint32_t element_size, uint32_t element_count);
static void write(const std::string & path, const std::vector<uint32_t> & elements);
static void write_samples(const std::string &path, const std::complex<float> * samples, uint32_t element_count);
static void write_samples(const std::string & path, const std::vector<std::complex<float>> & samples);
static std::vector<std::complex<float>> read_samples(const std::string & file_path, uint32_t offset, uint32_t total_samples);
static std::vector<uint32_t> get_data_carrier_indices(uint32_t fft_size);
static std::vector<std::complex<float>> extract_data_carriers(const std::vector<std::complex<float>> & symbol, uint32_t fft_size);
static std::string bit_vec_to_string(const std::vector<int8_t> & bit_vec);
static void print_bits(const std::vector<int8_t> & bits);
static uint32_t find_zc_seq_start_idx(const std::vector<std::complex<float>> & samples, double sample_rate);
static double radians_to_hz(double radians, double sample_rate);
static double hz_to_radians(double frequency, double sample_rate);
static std::vector<uint32_t> get_cyclic_prefix_schedule(double sample_rate);
static std::vector<std::pair<std::vector<std::complex<float>>, std::vector<std::complex<float>>>>
extract_ofdm_symbol_samples(const std::vector<std::complex<float>> & samples, double sample_rate, uint32_t offset);
static std::vector<std::complex<float>> calculate_channel(const std::vector<std::complex<float>> & symbol, double sample_rate, uint32_t symbol_idx);
static std::vector<int8_t> qpsk_to_bits(const std::vector<std::complex<float>> & samples);
static std::vector<float> angle(const std::vector<std::complex<float>> & samples) {
std::vector<float> angles(samples.size());
for (uint32_t idx = 0; idx < samples.size(); idx++) {
angles[idx] = std::arg(samples[idx]);
}
return angles;
}
static std::vector<float> abs_squared(const std::vector<std::complex<float>> & samples);
static std::vector<float> abs_squared(const std::vector<std::complex<float>> && samples);
misc_utils();
~misc_utils();
private:
};
} // namespace droneid
} // namespace gr
#endif /* INCLUDED_DRONEID_MISC_UTILS_H */

Wyświetl plik

@ -1,63 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DRONEID_NORMALIZED_XCORR_H
#define INCLUDED_DRONEID_NORMALIZED_XCORR_H
#include <droneid/api.h>
#include <vector>
#include <complex>
namespace gr {
namespace droneid {
/*!
* \brief <+description+>
*
*/
class DRONEID_API normalized_xcorr {
public:
using sample_t = float;
using complex_t = std::complex<sample_t>;
using complex_vec_t = std::vector<complex_t>;
explicit normalized_xcorr(const complex_vec_t & filter_taps);
uint32_t run(const complex_t * samples, uint32_t sample_count, sample_t * output_samples);
~normalized_xcorr();
protected:
complex_t * taps_;
complex_t * scores_;
uint32_t scores_size_;
double taps_var_;
uint32_t window_size_;
complex_t * temp_;
// complex_vec_t scores_;
complex_t scalar_;
private:
};
} // namespace droneid
} // namespace gr
#endif /* INCLUDED_DRONEID_NORMALIZED_XCORR_H */

Wyświetl plik

@ -1,54 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DRONEID_NORMALIZED_XCORR_ESTIMATE_H
#define INCLUDED_DRONEID_NORMALIZED_XCORR_ESTIMATE_H
#include <droneid/api.h>
#include <gnuradio/block.h>
namespace gr {
namespace droneid {
/*!
* \brief <+description of block+>
* \ingroup droneid
*
*/
class DRONEID_API normalized_xcorr_estimate : virtual public gr::block {
public:
typedef boost::shared_ptr<normalized_xcorr_estimate> sptr;
/*!
* \brief Return a shared_ptr to a new instance of droneid::normalized_xcorr_estimate.
*
* To avoid accidental use of raw pointers, droneid::normalized_xcorr_estimate's
* constructor is in a private implementation
* class. droneid::normalized_xcorr_estimate::make is the public interface for
* creating new instances.
*/
static sptr make(const std::vector<gr_complex> & /*taps*/);
};
} // namespace droneid
} // namespace gr
#endif /* INCLUDED_DRONEID_NORMALIZED_XCORR_ESTIMATE_H */

Wyświetl plik

@ -1,55 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DRONEID_TIME_SYNC_H
#define INCLUDED_DRONEID_TIME_SYNC_H
#include <droneid/api.h>
#include <gnuradio/sync_block.h>
namespace gr {
namespace droneid {
/*!
* \brief <+description of block+>
* \ingroup droneid
*
*/
class DRONEID_API time_sync : virtual public gr::sync_block
{
public:
typedef boost::shared_ptr<time_sync> sptr;
/*!
* \brief Return a shared_ptr to a new instance of droneid::time_sync.
*
* To avoid accidental use of raw pointers, droneid::time_sync's
* constructor is in a private implementation
* class. droneid::time_sync::make is the public interface for
* creating new instances.
*/
static sptr make(double sample_rate, const std::string & debug_path);
};
} // namespace droneid
} // namespace gr
#endif /* INCLUDED_DRONEID_TIME_SYNC_H */

Wyświetl plik

@ -1,55 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DRONEID_VARIANCE_H
#define INCLUDED_DRONEID_VARIANCE_H
#include <droneid/api.h>
#include <gnuradio/sync_block.h>
namespace gr {
namespace droneid {
/*!
* \brief <+description of block+>
* \ingroup droneid
*
*/
class DRONEID_API variance : virtual public gr::block
{
public:
typedef boost::shared_ptr<variance> sptr;
/*!
* \brief Return a shared_ptr to a new instance of droneid::variance.
*
* To avoid accidental use of raw pointers, droneid::variance's
* constructor is in a private implementation
* class. droneid::variance::make is the public interface for
* creating new instances.
*/
static sptr make(uint32_t window_size);
};
} // namespace droneid
} // namespace gr
#endif /* INCLUDED_DRONEID_VARIANCE_H */

Wyświetl plik

@ -0,0 +1,15 @@
# Copyright 2011,2012 Free Software Foundation, Inc.
#
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-droneid
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
########################################################################
# Install public header files
########################################################################
install(FILES
api.h
misc_utils.h DESTINATION include/gnuradio/droneid
)

Wyświetl plik

@ -0,0 +1,22 @@
/*
* Copyright 2011 Free Software Foundation, Inc.
*
* This file was generated by gr_modtool, a tool from the GNU Radio framework
* This file is a part of gr-droneid
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
*/
#ifndef INCLUDED_DRONEID_API_H
#define INCLUDED_DRONEID_API_H
#include <gnuradio/attributes.h>
#ifdef gnuradio_droneid_EXPORTS
#define DRONEID_API __GR_ATTR_EXPORT
#else
#define DRONEID_API __GR_ATTR_IMPORT
#endif
#endif /* INCLUDED_DRONEID_API_H */

Wyświetl plik

@ -0,0 +1,89 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef INCLUDED_DRONEID_MISC_UTILS_H
#define INCLUDED_DRONEID_MISC_UTILS_H
#include <gnuradio/droneid/api.h>
#include <vector>
#include <array>
#include <complex>
namespace gr {
namespace droneid {
/*!
* \brief <+description+>
*
*/
class DRONEID_API misc_utils {
public:
static constexpr double CARRIER_SPACING = 15e3;
static constexpr uint32_t OCCUPIED_CARRIERS_EXC_DC = 600;
static constexpr uint32_t OCCUPIED_CARRIERS_INC_DC = 601;
static uint32_t get_long_cp_len(double sample_rate);
static uint32_t get_short_cp_len(double sample_rate);
static uint32_t get_fft_size(double sample_rate);
static std::vector<std::complex<float>> create_gaussian_noise(uint32_t sample_count);
static std::vector<std::complex<float>> create_zc_sequence(double sample_rate, uint32_t root);
static std::vector<std::complex<float>> conj(const std::vector<std::complex<float>> & input);
static std::complex<float> mean(const std::complex<float> * samples, uint32_t sample_count);
static float var(const std::complex<float> * samples, uint32_t sample_count);
static float var_no_mean(const std::complex<float> * samples, uint32_t sample_count);
static void write(const std::string & path, const void * element, uint32_t element_size, uint32_t element_count);
static void write_vec(const std::string & path, const std::vector<uint32_t> & elements);
static void write_samples(const std::string &path, const std::complex<float> * samples, uint32_t element_count);
static void write_samples_vec(const std::string & path, const std::vector<std::complex<float>> & samples);
static std::vector<std::complex<float>> read_samples(const std::string & file_path, uint32_t offset, uint32_t total_samples);
static std::vector<uint32_t> get_data_carrier_indices(uint32_t fft_size);
static std::vector<std::complex<float>> extract_data_carriers(const std::vector<std::complex<float>> & symbol, uint32_t fft_size);
static std::string bit_vec_to_string(const std::vector<int8_t> & bit_vec);
static void print_bits(const std::vector<int8_t> & bits);
static uint32_t find_zc_seq_start_idx(const std::vector<std::complex<float>> & samples, double sample_rate);
static double radians_to_hz(double radians, double sample_rate);
static double hz_to_radians(double frequency, double sample_rate);
static std::vector<uint32_t> get_cyclic_prefix_schedule(double sample_rate);
static std::vector<std::pair<std::vector<std::complex<float>>, std::vector<std::complex<float>>>>
extract_ofdm_symbol_samples(const std::vector<std::complex<float>> & samples, double sample_rate, uint32_t offset);
static std::vector<std::complex<float>> calculate_channel(const std::vector<std::complex<float>> & symbol, double sample_rate, uint32_t symbol_idx);
static std::vector<int8_t> qpsk_to_bits(const std::vector<std::complex<float>> & samples);
static std::vector<float> angle(const std::vector<std::complex<float>> & samples) {
std::vector<float> angles(samples.size());
for (uint32_t idx = 0; idx < samples.size(); idx++) {
angles[idx] = std::arg(samples[idx]);
}
return angles;
}
static std::vector<float> abs_squared(const std::vector<std::complex<float>> & samples);
misc_utils();
~misc_utils();
private:
};
} // namespace droneid
} // namespace gr
#endif /* INCLUDED_DRONEID_MISC_UTILS_H */

Wyświetl plik

@ -3,20 +3,8 @@
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-droneid
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
# SPDX-License-Identifier: GPL-3.0-or-later
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
########################################################################
# Setup library
@ -24,16 +12,7 @@
include(GrPlatform) #define LIB_SUFFIX
list(APPEND droneid_sources
extractor_impl.cc
time_sync_impl.cc
utils.cpp
demodulation_impl.cc
misc_utils.cc
lte_decode.cc
decode_impl.cc
normalized_xcorr.cc
normalized_xcorr_estimate_impl.cc
variance_impl.cc
)
set(droneid_sources "${droneid_sources}" PARENT_SCOPE)
@ -43,11 +22,7 @@ if(NOT droneid_sources)
endif(NOT droneid_sources)
add_library(gnuradio-droneid SHARED ${droneid_sources})
# Compile with all optimizations on
target_compile_options(gnuradio-droneid PRIVATE -Ofast -march=native)
target_link_libraries(gnuradio-droneid gnuradio::gnuradio-runtime gnuradio::gnuradio-fft gnuradio::gnuradio-filter)
target_link_libraries(gnuradio-droneid turbofec)
target_link_libraries(gnuradio-droneid gnuradio::gnuradio-runtime)
target_include_directories(gnuradio-droneid
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
PUBLIC $<INSTALL_INTERFACE:include>
@ -81,31 +56,7 @@ include(GrTest)
#include_directories()
# List all files that contain Boost.UTF unit tests here
list(APPEND test_droneid_sources
qa_normalized_xcorr_estimate.cc
)
if (MATLAB_PATH)
message(STATUS "Using MATLAB path '${MATLAB_PATH}'")
if (NOT IS_DIRECTORY ${MATLAB_PATH})
message(FATAL_ERROR "MATLAB path '${MATLAB_PATH}' does not exist or is not a directory. Please fix or remove")
endif()
# Add paths to MATLAB libraries and headers
target_link_directories(gnuradio-droneid PUBLIC ${MATLAB_PATH}/extern/bin/glnxa64)
target_include_directories(gnuradio-droneid PUBLIC PUBLIC ${MATLAB_PATH}/extern/include)
# Add MATLAB library dependencies
target_link_libraries(gnuradio-droneid MatlabEngine MatlabDataArray)
list(APPEND test_droneid_sources
qa_variance.cc
qa_normalized_xcorr.cc
)
else()
message(WARNING "No MATLAB path specified, so some tests will be skipped")
endif()
# Anything we need to link to for the unit tests go here
list(APPEND GR_TEST_TARGET_DEPS gnuradio-droneid)
@ -118,4 +69,4 @@ foreach(qa_file ${test_droneid_sources})
GR_ADD_CPP_TEST("droneid_${qa_file}"
${CMAKE_CURRENT_SOURCE_DIR}/${qa_file}
)
endforeach(qa_file)
endforeach(qa_file)

Wyświetl plik

@ -1,189 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
extern "C" {
#include <turbofec/rate_match.h>
#include <turbofec/turbo.h>
}
#include <gnuradio/io_signature.h>
#include "decode_impl.h"
#include <boost/filesystem.hpp>
#include "droneid/misc_utils.h"
#include <chrono>
// This line is required before the include of CRC.h so that it actually loads the CRC_24_LTEA definition
#define CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS
#include <CRC.h>
namespace gr {
namespace droneid {
using path = boost::filesystem::path;
decode::sptr
decode::make(const std::string & debug_path) {
return gnuradio::get_initial_sptr
(new decode_impl(debug_path));
}
/*
* The private constructor
*/
decode_impl::decode_impl(const std::string & debug_path)
: gr::sync_block("decode",
gr::io_signature::make(0, 0, 0),
gr::io_signature::make(0, 0, 0)),
debug_path_(debug_path){
message_port_register_in(pmt::mp(input_pdu_port_name_));
message_port_register_out(pmt::mp(output_pdu_port_name_));
set_msg_handler(pmt::mp(input_pdu_port_name_), [this](const pmt::pmt_t & pdu){
this->handle_pdu(pdu);
});
}
/*
* Our virtual destructor.
*/
decode_impl::~decode_impl() {
}
std::vector<int8_t> decode_impl::qpsk_to_bits(const std::vector<gr_complex> &samples) {
std::vector<int8_t> bits(samples.size() * 2);
auto * bit_vec_ptr = &bits[0];
std::for_each(samples.begin(), samples.end(), [&bit_vec_ptr](const gr_complex & sample) {
if (sample.real() > 0 && sample.imag() > 0) {
*bit_vec_ptr++ = 0;
*bit_vec_ptr++ = 0;
} else if (sample.real() > 0 && sample.imag() < 0) {
*bit_vec_ptr++ = 0;
*bit_vec_ptr++ = 1;
} else if (sample.real() < 0 && sample.imag() > 0) {
*bit_vec_ptr++ = 1;
*bit_vec_ptr++ = 0;
} else {
*bit_vec_ptr++ = 1;
*bit_vec_ptr++ = 1;
}
});
return bits;
}
void decode_impl::handle_pdu(const pmt::pmt_t & pdu) {
const auto start_time = std::chrono::high_resolution_clock::now();
const pmt::pmt_t meta = pmt::car(pdu);
const pmt::pmt_t vec = pmt::cdr(pdu);
const auto samples = pmt::c32vector_elements(vec);
if (samples.size() != 3600) {
std::cout << "Invalid number of samples. Expected 3600, got " << samples.size() << "\n";
return;
}
auto bits = qpsk_to_bits(samples);
if (! debug_path_.empty()) {
misc_utils::write((path(debug_path_) / "bits").string(), &bits[0], sizeof(bits[0]), bits.size());
const auto bit_string = misc_utils::bit_vec_to_string(bits);
misc_utils::write((path(debug_path_) / "bit_string").string(), &bit_string[0], sizeof(bit_string[0]), bit_string.size());
}
// misc_utils::print_bits(bits);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Setup and run the Turbo decoder
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const size_t input_file_bit_count = 7200;
const int turbo_iterations = 4;
const int turbo_decoder_bit_count = 1412; // Number of bits that the Turbo decoder will take in
const int expected_payload_bytes = 176; // Number of bytes that the Turbo decoder will output
const int expected_payload_bits = expected_payload_bytes * 8;
// Allocate buffers for the Turbo decoder
std::vector<int8_t> d1(turbo_decoder_bit_count);
std::vector<int8_t> d2(turbo_decoder_bit_count);
std::vector<int8_t> d3(turbo_decoder_bit_count);
std::vector<uint8_t> decoded_bytes(expected_payload_bytes);
// Create the required structures to run the Turbo decoder
struct lte_rate_matcher * rate_matcher = lte_rate_matcher_alloc();
struct tdecoder * turbo_decoder = alloc_tdec();
struct lte_rate_matcher_io rate_matcher_io = {
.D = turbo_decoder_bit_count,
.E = input_file_bit_count,
.d = {&d1[0], &d2[0], &d3[0]},
.e = &bits[0]
};
// Setup the rate matching logic
lte_rate_match_rv(rate_matcher, &rate_matcher_io, 0);
// Run the turbo decoder (will do rate matching as well)
const int decode_status = lte_turbo_decode(turbo_decoder, expected_payload_bits, turbo_iterations,
&decoded_bytes[0], &d1[0], &d2[0], &d3[0]);
if (decode_status != 0) {
std::cerr << "Failed to decode\n";
} else {
for (const auto & b : decoded_bytes) {
fprintf(stdout, "%02x", b);
}
fprintf(stdout, "\n");
const auto crc_out = CRC::Calculate(&decoded_bytes[0], decoded_bytes.size(), CRC::CRC_24_LTEA());
if (crc_out != 0) {
std::cerr << "CRC Check Failed!\n";
}
message_port_pub(pmt::mp(output_pdu_port_name_), pmt::cons(pmt::make_dict(), pmt::init_u8vector(decoded_bytes.size(), decoded_bytes)));
}
free_tdec(turbo_decoder);
lte_rate_matcher_free(rate_matcher);
const auto end_time = std::chrono::high_resolution_clock::now();
std::cout << "Time: " << std::chrono::duration<float>(end_time - start_time).count() << "\n";
}
int
decode_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items) {
// Do <+signal processing+>
// Tell runtime system how many output items we produced.
return noutput_items;
}
} /* namespace droneid */
} /* namespace gr */

Wyświetl plik

@ -1,61 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DRONEID_DECODE_IMPL_H
#define INCLUDED_DRONEID_DECODE_IMPL_H
#include <vector>
#include <droneid/decode.h>
namespace gr {
namespace droneid {
class decode_impl : public decode {
private:
const std::string input_pdu_port_name_ = "pdus";
const std::string output_pdu_port_name_ = "pdus";
const std::string debug_path_;
static std::vector<int8_t> qpsk_to_bits(const std::vector<gr_complex> & samples);
// Nothing to declare in this block.
public:
decode_impl(const std::string & debug_path);
~decode_impl();
// Where all the action really happens
int work(
int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items
);
void handle_pdu(const pmt::pmt_t & pdu);
};
} // namespace droneid
} // namespace gr
#endif /* INCLUDED_DRONEID_DECODE_IMPL_H */

Wyświetl plik

@ -1,496 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <boost/filesystem.hpp>
#include <gnuradio/io_signature.h>
#include "demodulation_impl.h"
#include "droneid/misc_utils.h"
#include <volk/volk.h>
#include <gnuradio/fft/fft.h>
#include <gnuradio/fft/fft_shift.h>
#include <numeric>
#include <droneid/lte_decode.h>
namespace gr {
namespace droneid {
using path = boost::filesystem::path;
using utils = misc_utils;
demodulation::sptr
demodulation::make(double sample_rate, const std::string & debug_path) {
return gnuradio::get_initial_sptr
(new demodulation_impl(sample_rate, debug_path));
}
/*
* The private constructor
*/
demodulation_impl::demodulation_impl(const double sample_rate, const std::string & debug_path)
: gr::sync_block("demodulation",
gr::io_signature::make(0, 0, 0),
gr::io_signature::make(0, 0, 0)),
sample_rate_(sample_rate), fft_size_(misc_utils::get_fft_size(sample_rate)), long_cp_len_(
misc_utils::get_long_cp_len(sample_rate)), short_cp_len_(misc_utils::get_short_cp_len(sample_rate)),
debug_path_(debug_path){
if (! debug_path_.empty()) {
const auto p = path(debug_path_);
if (! boost::filesystem::is_directory(p)) {
boost::filesystem::create_directories(p);
}
}
message_port_register_in(pmt::mp("pdus"));
message_port_register_out(pmt::mp("pdus"));
set_msg_handler(pmt::mp("pdus"), [this](pmt::pmt_t pdu){handle_msg(pdu);});
cfo_cp_len_ = short_cp_len_;
burst_counter_ = 0;
cfo_buffer_.resize(cfo_cp_len_ * 2);
// sample_buffer_.resize((fft_size_ * 9) + (long_cp_len_ * 2) + (short_cp_len_ * 7));
cp_lengths_ = {
long_cp_len_,
short_cp_len_,
short_cp_len_,
short_cp_len_,
short_cp_len_,
short_cp_len_,
short_cp_len_,
short_cp_len_,
long_cp_len_
};
symbols_.resize(cp_lengths_.size());
for (auto & vec : symbols_) {
vec.resize(fft_size_);
}
std::cout << "FFT SIZE: " << fft_size_ << ", sample rate: " << sample_rate_ << "\n";
zc_ = misc_utils::create_zc_sequence(sample_rate_, 600);
fft_ = std::unique_ptr<gr::fft::fft_complex>(new gr::fft::fft_complex(static_cast<int>(fft_size_), true, 1));
fft_shift_ = std::unique_ptr<gr::fft::fft_shift<std::complex<float>>>(new gr::fft::fft_shift<std::complex<float>>(fft_size_));
std::copy(zc_.begin(), zc_.end(), fft_->get_inbuf());
fft_->execute();
std::copy(fft_->get_outbuf(), fft_->get_outbuf() + fft_size_, zc_.begin());
std::for_each(zc_.begin(), zc_.end(), [this](std::complex<float> & sample){ sample /= static_cast<float>(fft_size_);});
fft_shift_->shift(zc_);
channel_.resize(fft_size_);
if (! debug_path_.empty()) {
misc_utils::write_samples((path(debug_path_) / "zc").string(), zc_);
}
}
/*
* Our virtual destructor.
*/
demodulation_impl::~demodulation_impl() {
}
void demodulation_impl::handle_msg(pmt::pmt_t pdu) {
burst_counter_++;
const auto meta = pmt::car(pdu);
const auto vec = pmt::cdr(pdu);
const std::complex<float> I = {0, 1};
std::vector<std::complex<float>> samples(pmt::c32vector_elements(vec));
if (! debug_path_.empty()) {
misc_utils::write_samples((path(debug_path_) / ("burst_" + std::to_string(burst_counter_))).string(), samples);
}
if (sample_buffer_.size() < samples.size()) {
sample_buffer_.resize(samples.size());
}
const auto start_idx_pmt = pmt::dict_ref(meta, pmt::mp("start_idx"), pmt::from_uint64(0));
const auto start_idx = pmt::to_uint64(start_idx_pmt);
/////////////////////////////////////////////////////////////////////////////////////
/// Find the ZC sequence
/////////////////////////////////////////////////////////////////////////////////////
const auto zc_start_idx = utils::find_zc_seq_start_idx(samples, sample_rate_);
const auto est_start_index = zc_start_idx - (fft_size_ * 3) - long_cp_len_ - (short_cp_len_ * 3);
std::cout << "ZC start index: " << zc_start_idx << ", est start index: " << est_start_index << "\n";
const auto total_sample_count = est_start_index + (fft_size_ * 9) + (long_cp_len_ * 2) + (short_cp_len_ * 7);
if (est_start_index > samples.size() || total_sample_count > samples.size()) {
std::cout << "Did not receive enough samples! Skipping burst\n";
return;
}
/////////////////////////////////////////////////////////////////////////////////////
/// Coarse CFO estimate
/////////////////////////////////////////////////////////////////////////////////////
const auto cfo_backoff = 16;
const auto cfo_size = short_cp_len_ - (cfo_backoff * 2);
const std::vector<std::complex<float>> zc_seq_full_symbol(
&samples[zc_start_idx - short_cp_len_], &samples[zc_start_idx + fft_size_]);
const std::vector<std::complex<float>> cyclic_prefix(
zc_seq_full_symbol.begin() + cfo_backoff, zc_seq_full_symbol.begin() + cfo_backoff + cfo_size);
const std::vector<std::complex<float>> end_of_symbol(
zc_seq_full_symbol.end() - cfo_backoff - cfo_size, zc_seq_full_symbol.end() - cfo_backoff);
if (! debug_path_.empty()) {
misc_utils::write_samples((path(debug_path_) / ("received_zc_" + std::to_string(burst_counter_))).string(), zc_seq_full_symbol);
misc_utils::write_samples((path(debug_path_) / ("expected_zc_" + std::to_string(burst_counter_))).string(), zc_);
misc_utils::write_samples((path(debug_path_) / ("cfo_estimate_cyclic_prefix_" + std::to_string(burst_counter_))).string(), cyclic_prefix);
misc_utils::write_samples((path(debug_path_) / ("cfo_estimate_end_of_symbol_" + std::to_string(burst_counter_))).string(), end_of_symbol);
}
std::complex<float> cfo_dot_prod {0, 0};
for (uint32_t idx = 0; idx < cyclic_prefix.size(); idx++) {
cfo_dot_prod += cyclic_prefix[idx] * std::conj(end_of_symbol[idx]);
}
const auto cfo_angle = std::arg(cfo_dot_prod) / static_cast<float>(fft_size_);
const auto cfo_phase_angle = std::exp(I * -cfo_angle);
/////////////////////////////////////////////////////////////////////////////////////
/// Coarse CFO correction
/////////////////////////////////////////////////////////////////////////////////////
std::complex<float> starting_cfo_phase {1, 0};
volk_32fc_s32fc_x2_rotator_32fc(&samples[0], &samples[0], cfo_phase_angle, &starting_cfo_phase, samples.size());
if (! debug_path_.empty()) {
misc_utils::write_samples((path(debug_path_) / ("burst_post_coarse_cfo_correction_" + std::to_string(burst_counter_))).string(), samples);
}
/////////////////////////////////////////////////////////////////////////////////////
/// Channel estimation
/////////////////////////////////////////////////////////////////////////////////////
const auto symbols = utils::extract_ofdm_symbol_samples(samples, sample_rate_, est_start_index);
const auto zc_symbol_4_freq_domain = symbols[3].second;
const auto zc_symbol_6_freq_domain = symbols[5].second;
const auto zc_4_data_only = utils::extract_data_carriers(zc_symbol_4_freq_domain, fft_size_);
const auto zc_6_data_only = utils::extract_data_carriers(zc_symbol_6_freq_domain, fft_size_);
// utils::write_samples("/tmp/symbol_4", zc_4_data_only);
// utils::write_samples("/tmp/symbol_6", zc_6_data_only);
const auto zc_4_channel = utils::calculate_channel(zc_4_data_only, sample_rate_, 4);
const auto zc_6_channel = utils::calculate_channel(zc_6_data_only, sample_rate_, 6);
// utils::write_samples("/tmp/channel_4", zc_4_channel);
// utils::write_samples("/tmp/channel_6", zc_6_channel);
const auto zc_4_channel_angles = utils::angle(zc_4_channel);
const auto zc_6_channel_angles = utils::angle(zc_6_channel);
const auto zc_4_channel_phase = std::accumulate(zc_4_channel_angles.begin(), zc_4_channel_angles.end(), 0.0f) / 600;
const auto zc_6_channel_phase = std::accumulate(zc_6_channel_angles.begin(), zc_6_channel_angles.end(), 0.0f) / 600;
// std::cout << "4 phase: " << zc_4_channel_phase << "\n";
// std::cout << "6 phase: " << zc_6_channel_phase << "\n";
const auto channel_phase_adj = (zc_4_channel_phase - zc_6_channel_phase) / 2;
/////////////////////////////////////////////////////////////////////////////////////
/// Save Constellation
/////////////////////////////////////////////////////////////////////////////////////
std::vector<std::complex<float>> all_data_carriers;
for (int idx = 0; idx < 9; idx++) {
if (idx == 1 || idx == 3 || idx == 5) {
continue;
}
auto data_carriers = utils::extract_data_carriers(symbols[idx].second, fft_size_);
for(uint32_t i = 0; i < 600; i++) {
data_carriers[i] *= zc_4_channel[i];
// data_carriers[i] *= std::exp(I * (-channel_phase_adj * static_cast<float>(idx - 6)));
}
all_data_carriers.insert(all_data_carriers.end(), data_carriers.begin(), data_carriers.end());
}
message_port_pub(pmt::mp("pdus"), pmt::cons(pmt::make_dict(), pmt::init_c32vector(all_data_carriers.size(), all_data_carriers)));
// utils::write_samples("/tmp/all_data", all_data_carriers);
/////////////////////////////////////////////////////////////////////////////////////
/// QPSK to bits
/////////////////////////////////////////////////////////////////////////////////////
auto bits = utils::qpsk_to_bits(all_data_carriers);
for (int idx = 0; idx < 7200; idx++) {
if (bits[idx] == 1 && XOR_BIT_VEC[idx] == 1) {
bits[idx] = 0;
} else if (bits[idx] == 0 && XOR_BIT_VEC[idx] == 0) {
bits[idx] = 0;
} else {
bits[idx] = 1;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Setup and run the Turbo decoder
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const size_t input_file_bit_count = 7200;
const int turbo_iterations = 4;
const int turbo_decoder_bit_count = 1412; // Number of bits that the Turbo decoder will take in
const int expected_payload_bytes = 176; // Number of bytes that the Turbo decoder will output
const int expected_payload_bits = expected_payload_bytes * 8;
// Allocate buffers for the Turbo decoder
std::vector<int8_t> d1(turbo_decoder_bit_count);
std::vector<int8_t> d2(turbo_decoder_bit_count);
std::vector<int8_t> d3(turbo_decoder_bit_count);
std::vector<uint8_t> decoded_bytes(expected_payload_bytes);
// Create the required structures to run the Turbo decoder
struct lte_rate_matcher * rate_matcher = lte_rate_matcher_alloc();
struct tdecoder * turbo_decoder = alloc_tdec();
struct lte_rate_matcher_io rate_matcher_io = {
.D = turbo_decoder_bit_count,
.E = input_file_bit_count,
.d = {&d1[0], &d2[0], &d3[0]},
.e = &bits[0]
};
// Setup the rate matching logic
lte_rate_match_rv(rate_matcher, &rate_matcher_io, 0);
// Run the turbo decoder (will do rate matching as well)
const int decode_status = lte_turbo_decode(turbo_decoder, expected_payload_bits, turbo_iterations,
&decoded_bytes[0], &d1[0], &d2[0], &d3[0]);
if (decode_status != 0) {
std::cerr << "Failed to decode\n";
} else {
for (const auto & b : decoded_bytes) {
fprintf(stdout, "%02x", b);
}
fprintf(stdout, "\n");
const auto crc_out = CRC::Calculate(&decoded_bytes[0], decoded_bytes.size(), CRC::CRC_24_LTEA());
if (crc_out != 0) {
std::cerr << "CRC Check Failed!\n";
}
}
free_tdec(turbo_decoder);
lte_rate_matcher_free(rate_matcher);
}
int
demodulation_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items) {
// Do <+signal processing+>
// Tell runtime system how many output items we produced.
return noutput_items;
}
const uint8_t demodulation_impl::XOR_BIT_VEC[7200] = {
1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1
, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0
, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0
, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0
, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0
, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0
, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0
, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0
, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0
, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1
, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1
, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0
, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1
, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0
, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1
, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1
, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0
, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0
, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0
, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0
, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0
, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1
, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0
, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0
, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0
, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1
, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0
, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0
, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1
, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1
, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0
, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1
, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1
, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0
, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1
, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0
, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0
, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0
, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1
, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0
, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0
, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0
, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0
, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0
, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1
, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0
, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1
, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1
, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0
, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1
, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0
, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0
, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0
, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1
, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0
, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1
, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1
, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1
, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0
, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0
, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1
, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0
, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0
, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0
, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0
, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0
, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1
, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1
, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0
, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1
, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0
, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1
, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1
, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1
, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0
, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0
, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1
, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0
, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1
, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1
, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1
, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0
, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0
, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0
, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1
, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1
, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1
, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1
, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1
, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1
, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1
, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0
, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1
, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0
, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1
, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1
, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1
, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1
, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0
, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0
, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0
, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0
, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1
, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1
, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0
, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0
, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0
, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0
, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1
, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1
, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0
, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0
, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0
, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0
, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0
, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1
, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1
, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1
, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0
, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1
, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1
, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0
, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0
, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1
, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1
, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1
, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1
, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1
, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0
, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1
, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1
, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1
, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0
, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1
, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1
, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0
, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0
, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0
, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1
, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0
, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1
, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0
, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0
, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1
, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0
, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1
, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0
, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1
, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1
, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0
, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0
, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1
, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1
, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1
, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1
, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1
, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1
, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1
, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0
, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1
, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1
, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0
, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1
, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1
, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0
, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0
, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0
, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0
, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1
, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0
, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0
, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0
, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0
, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1
, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1
, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0
, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1
, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1
, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1
};
} /* namespace droneid */
} /* namespace gr */

Wyświetl plik

@ -1,73 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DRONEID_DEMODULATION_IMPL_H
#define INCLUDED_DRONEID_DEMODULATION_IMPL_H
#include <droneid/demodulation.h>
#include <gnuradio/fft/fft.h>
#include <gnuradio/fft/fft_shift.h>
namespace gr {
namespace droneid {
class demodulation_impl : public demodulation {
private:
const double sample_rate_;
const uint32_t fft_size_;
const uint32_t long_cp_len_;
const uint32_t short_cp_len_;
const std::string debug_path_;
const static uint8_t XOR_BIT_VEC [7200];
std::unique_ptr<gr::fft::fft_complex> fft_;
std::unique_ptr<gr::fft::fft_shift<std::complex<float>>> fft_shift_;
uint32_t burst_counter_;
size_t sample_count_;
uint32_t cfo_cp_len_;
std::vector<uint32_t> cp_lengths_;
std::vector<std::complex<float>> zc_;
std::vector<std::complex<float>> channel_;
std::vector<std::vector<std::complex<float>>> symbols_;
std::vector<std::complex<float>> cfo_buffer_;
std::vector<std::complex<float>> sample_buffer_;
void handle_msg(pmt::pmt_t pdu);
// Nothing to declare in this block.
public:
demodulation_impl(double sample_rate, const std::string & debug_path);
~demodulation_impl();
// Where all the action really happens
int work(
int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items
);
};
} // namespace droneid
} // namespace gr
#endif /* INCLUDED_DRONEID_DEMODULATION_IMPL_H */

Wyświetl plik

@ -1,119 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "extractor_impl.h"
#include "droneid/misc_utils.h"
namespace gr {
namespace droneid {
extractor::sptr
extractor::make(const double sample_rate, const float threshold) {
return gnuradio::get_initial_sptr
(new extractor_impl(sample_rate, threshold));
}
/*
* The private constructor
*/
extractor_impl::extractor_impl(double sample_rate, const float threshold)
: gr::sync_block("extractor",
gr::io_signature::make2(2, 2, sizeof(gr_complex), sizeof(float)),
gr::io_signature::make(0, 0, 0)), fft_size_(misc_utils::get_fft_size(sample_rate)),
long_cp_len_(misc_utils::get_long_cp_len(sample_rate)), short_cp_len_(misc_utils::get_short_cp_len(sample_rate)),
extract_samples_count_((fft_size_ * 13) + (long_cp_len_ * 2) + (short_cp_len_ * 7)){
this->message_port_register_out(pmt::mp("pdus"));
buffer_.resize(extract_samples_count_);
current_state_ = state_t::WAITING_FOR_THRESHOLD;
collected_samples_ = 0;
total_samples_read_ = 0;
threshold_ = threshold;
}
/*
* Our virtual destructor.
*/
extractor_impl::~extractor_impl() {
}
void extractor_impl::set_threshold(const float threshold) {
std::lock_guard<decltype(parameter_lock_)> l(parameter_lock_);
threshold_ = threshold;
}
int
extractor_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items) {
const gr_complex *samples = (const gr_complex *) input_items[0];
const float *correlation_scores = (const float *) input_items[1];
float threshold;
{
std::lock_guard<decltype(parameter_lock_)> lock(parameter_lock_);
threshold = threshold_;
}
for (int idx = 0; idx < noutput_items; idx++) {
total_samples_read_++;
switch (current_state_) {
case state_t::WAITING_FOR_THRESHOLD: {
if (correlation_scores[idx] > threshold) {
start_sample_index_ = nitems_read(0) + idx;
std::cout << "Found burst @ " << total_samples_read_ << " / " << start_sample_index_ << "\n";
current_state_ = state_t::COLLECTING_SAMPLES;
collected_samples_ = 1;
buffer_[0] = samples[idx];
}
break;
}
case state_t::COLLECTING_SAMPLES: {
buffer_[collected_samples_++] = samples[idx];
if (collected_samples_ == extract_samples_count_) {
current_state_ = state_t::WAITING_FOR_THRESHOLD;
const pmt::pmt_t vec = pmt::init_c32vector(buffer_.size(), buffer_);
pmt::pmt_t meta = pmt::make_dict();
meta = pmt::dict_add(meta, pmt::mp("start_offset"), pmt::from_uint64(start_sample_index_));
std::cout << "Sending message with " << pmt::length(vec) << " elements (" << extract_samples_count_ << ") starting at " << start_sample_index_ << "\n";
message_port_pub(pmt::mp("pdus"), pmt::cons(meta, vec));
collected_samples_ = 0;
}
break;
}
}
}
// Do <+signal processing+>
// Tell runtime system how many output items we produced.
return noutput_items;
}
} /* namespace droneid */
} /* namespace gr */

Wyświetl plik

@ -1,70 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DRONEID_EXTRACTOR_IMPL_H
#define INCLUDED_DRONEID_EXTRACTOR_IMPL_H
#include <droneid/extractor.h>
namespace gr {
namespace droneid {
class extractor_impl : public extractor {
private:
enum class state_t {
WAITING_FOR_THRESHOLD,
COLLECTING_SAMPLES
};
static constexpr float CARRIER_SPACING = 15e3;
uint64_t start_sample_index_;
uint64_t total_samples_read_;
state_t current_state_;
uint32_t collected_samples_;
const uint32_t fft_size_;
const uint32_t long_cp_len_;
const uint32_t short_cp_len_;
const uint32_t extract_samples_count_;
std::vector<gr_complex> buffer_;
float threshold_;
std::mutex parameter_lock_;
public:
extractor_impl(double sample_rate, float threshold);
~extractor_impl();
void set_threshold(float threshold) override;
// Where all the action really happens
int work(
int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items
);
};
} // namespace droneid
} // namespace gr
#endif /* INCLUDED_DRONEID_EXTRACTOR_IMPL_H */

Wyświetl plik

@ -1,98 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include <droneid/lte_decode.h>
#include <iostream>
namespace gr {
namespace droneid {
lte_decode::lte_decode() {
d1_.resize(TURBO_DECODER_BIT_COUNT);
d2_.resize(TURBO_DECODER_BIT_COUNT);
d3_.resize(TURBO_DECODER_BIT_COUNT);
turbo_decoder_input_.resize(TURBO_DECODER_INPUT_BIT_COUNT);
decoded_bytes_.resize(EXPECTED_PAYLOAD_BYTES);
rate_matcher_ = lte_rate_matcher_alloc();
turbo_decoder_ = alloc_tdec();
rate_matcher_io_ = {
.D = TURBO_DECODER_BIT_COUNT,
.E = TURBO_DECODER_INPUT_BIT_COUNT,
.d = {&d1_[0], &d2_[0], &d3_[0]},
.e = &turbo_decoder_input_[0]
};
}
lte_decode::~lte_decode() {
if (rate_matcher_ != nullptr) {
lte_rate_matcher_free(rate_matcher_);
}
if (turbo_decoder_ != nullptr) {
free_tdec(turbo_decoder_);
}
}
std::vector<uint8_t> lte_decode::decode(const std::vector<int8_t> &bits) {
if (bits.size() != TURBO_DECODER_INPUT_BIT_COUNT) {
std::ostringstream err;
err << "Turbo decoder expected " << TURBO_DECODER_INPUT_BIT_COUNT << " but got " << bits.size();
throw std::runtime_error(err.str());
}
int8_t bit_lut[2] = {-63, 63};
std::vector<int8_t> bits_copy = bits;
for (int idx = 0; idx < bits.size(); idx++) {
turbo_decoder_input_[idx] = bit_lut[bits[idx]];
}
lte_rate_match_fw(rate_matcher_, &rate_matcher_io_, 0);
const int decode_status = lte_turbo_decode(turbo_decoder_, EXPECTED_PAYLOAD_BITS, TURBO_ITERATIONS,
&decoded_bytes_[0], &d1_[0], &d2_[0], &d3_[0]);
fprintf(stdout, "MOO: ");
for (const auto & i : decoded_bytes_) {
fprintf(stdout, "%02x", i);
}
fprintf(stdout, "\n");
if (decode_status != 0) {
throw std::runtime_error("Failed to remove Turbo code. Status: " + std::to_string(decode_status));
}
const uint32_t calculated_crc = CRC::Calculate(&decoded_bytes_[0], decoded_bytes_.size(), CRC::CRC_24_LTEA());
if (calculated_crc != 0) {
return {};
}
return decoded_bytes_;
}
} /* namespace droneid */
} /* namespace gr */

Wyświetl plik

@ -2,30 +2,13 @@
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/droneid/misc_utils.h>
#include <gnuradio/io_signature.h>
#include <numeric>
#include <gnuradio/io_signature.h>
#include <droneid/misc_utils.h>
#include <gnuradio/fft/fft.h>
#include <gnuradio/fft/fft_shift.h>
#include <gnuradio/random.h>
@ -34,382 +17,366 @@
#include <volk/volk.h>
namespace gr {
namespace droneid {
namespace droneid {
misc_utils::misc_utils() {
misc_utils::misc_utils() {
}
misc_utils::~misc_utils() {
}
uint32_t misc_utils::get_long_cp_len(double sample_rate) {
return static_cast<uint32_t>(std::round(sample_rate / 192000));
}
uint32_t misc_utils::get_short_cp_len(double sample_rate) {
return static_cast<uint32_t>(round(0.0000046875 * sample_rate));
}
uint32_t misc_utils::get_fft_size(double sample_rate) {
return static_cast<uint32_t>(round(sample_rate / CARRIER_SPACING));
}
std::vector<std::complex<float>> misc_utils::create_zc_sequence(const double sample_rate, const uint32_t root) {
const auto fft_size = get_fft_size(sample_rate);
std::vector<std::complex<float>> sequence(fft_size, {0, 0});
const uint32_t guard_carriers = fft_size - OCCUPIED_CARRIERS_EXC_DC;
const auto left_guards = guard_carriers / 2;
std::vector<std::complex<float>> g (OCCUPIED_CARRIERS_INC_DC);
const auto I = std::complex<double>(0, 1);
for (int idx = 0; idx < OCCUPIED_CARRIERS_INC_DC; idx++) {
// Doing the arith below in double precision and then casting down to a float. Using floats the whole
// way will result in an output that's very far off from the MATLAB implementation. The errors will accumulate
// down the vector
sequence[left_guards + idx] = std::exp(-I * (M_PIf64 * (double)root * (double)idx * (double)(idx + 1) / 601.0));
}
// Null out the DC carrier
sequence[(fft_size / 2)] = 0;
// Create an FFT object that is configured to run an inverse FFT
gr::fft::fft_complex_rev ifft(static_cast<int>(fft_size), false);
// FFT-shift the inputs (swap the left and right halves) and store in the IFFT input buffer
std::copy(sequence.begin() + (fft_size/2), sequence.begin() + fft_size, ifft.get_inbuf());
std::copy(sequence.begin(), sequence.begin() + (fft_size/2), ifft.get_inbuf() + (fft_size/2));
// Run the IFFT
ifft.execute();
// Copy the IFFT'd samples out
std::copy(ifft.get_outbuf(), ifft.get_outbuf() + fft_size, sequence.begin());
// The samples need to be scaled by the FFT size to get the power back down
std::for_each(sequence.begin(), sequence.end(), [fft_size](std::complex<float> & sample){sample /= static_cast<float>(fft_size);});
return sequence;
}
std::vector<std::complex<float>> misc_utils::conj(const std::vector<std::complex<float>> &input) {
auto vec = input;
std::for_each(vec.begin(), vec.end(), [](std::complex<float> & sample){sample = std::conj(sample);});
return vec;
}
void misc_utils::write_samples_vec(const std::string &path, const std::vector<std::complex<float>> &samples) {
write_samples(path, &samples[0], samples.size());
}
void misc_utils::write_samples(const std::string &path, const std::complex<float> * const samples, const uint32_t element_count) {
write(path, samples, sizeof(samples[0]), element_count);
}
std::vector<uint32_t> misc_utils::get_data_carrier_indices(const uint32_t fft_size) {
std::vector<uint32_t> data_carrier_indices(600, 0);
auto * ptr = &data_carrier_indices[0];
for (uint32_t idx = (fft_size / 2) - 300; idx < (fft_size / 2) + 301; idx++) {
if (idx != fft_size / 2) {
*ptr++ = idx;
}
}
misc_utils::~misc_utils() {
return data_carrier_indices;
}
std::vector<std::complex<float>> misc_utils::extract_data_carriers(const std::vector<std::complex<float>> & symbol, const uint32_t fft_size) {
const auto data_carrier_indices = get_data_carrier_indices(fft_size);
std::vector<std::complex<float>> data_carriers(data_carrier_indices.size());
auto iter = data_carriers.begin();
for (const auto & index : data_carrier_indices) {
*iter++ = symbol[index];
}
return data_carriers;
}
void
misc_utils::write(const std::string &path, const void * const elements, const uint32_t element_size, const uint32_t element_count) {
FILE * handle = fopen(path.c_str(), "wb");
if (!handle) {
throw std::runtime_error("Failed to open output file");
}
fwrite(elements, element_size, element_count, handle);
fclose(handle);
}
void misc_utils::write_vec(const std::string &path, const std::vector<uint32_t> &elements) {
write(path, &elements[0], sizeof(elements[0]), elements.size());
}
void misc_utils::print_bits(const std::vector<int8_t> & bits) {
std::ostringstream buff;
for (const auto & bit : bits) {
buff << (bit == 0 ? 0 : 1);
}
buff << "\n";
std::cout << buff.str();
std::flush(std::cout);
}
std::string misc_utils::bit_vec_to_string(const std::vector<int8_t> &bit_vec) {
std::ostringstream buff;
char lut[2] = {'0', '1'};
for (const auto & bit : bit_vec) {
buff << lut[bit];
}
return buff.str();
}
uint32_t
misc_utils::find_zc_seq_start_idx(const std::vector<std::complex<float>> & samples, const double sample_rate) {
const auto fft_size = get_fft_size(sample_rate);
std::vector<float> scores(samples.size() - fft_size);
std::vector<std::complex<float>> window_one(fft_size / 2);
std::vector<std::complex<float>> window_two(fft_size / 2);
auto window_one_iter = samples.begin();
auto window_two_iter = samples.begin() + (fft_size / 2);
std::vector<std::complex<float>> dot_prods(scores.size(), 0);
for (uint32_t idx = 0; idx < scores.size(); idx++) {
std::copy(window_one_iter, window_one_iter + (fft_size / 2), window_one.begin());
std::copy(window_two_iter, window_two_iter + (fft_size / 2), window_two.begin());
window_one_iter++;
window_two_iter++;
std::reverse(window_two.begin(), window_two.end());
for (int i = 0; i < fft_size / 2; i++) {
dot_prods[idx] += window_one[i] * std::conj(window_two[i]);
}
}
uint32_t misc_utils::get_long_cp_len(double sample_rate) {
return static_cast<uint32_t>(std::round(sample_rate / 192000));
volk_32fc_magnitude_squared_32f(&scores[0], &dot_prods[0], dot_prods.size());
gr::droneid::misc_utils::write_samples_vec("/tmp/dots", dot_prods);
gr::droneid::misc_utils::write("/tmp/scores", &scores[0], sizeof(scores[0]), scores.size());
uint32_t max_idx;
volk_32f_index_max_32u(&max_idx, &scores[0], scores.size());
return max_idx;
}
std::vector<std::complex<float>>
misc_utils::read_samples(const std::string &file_path, uint32_t offset, uint32_t total_samples) {
const auto element_size = sizeof(std::complex<float>);
std::vector<std::complex<float>> samples;
FILE * file_handle = fopen(file_path.c_str(), "r");
if (! file_handle) {
throw std::runtime_error("File '" + file_path + "' could not be opened");
}
fseek(file_handle, 0, SEEK_END);
const auto available_samples = static_cast<uint32_t>(static_cast<double>(ftell(file_handle)) / element_size);
if (available_samples < offset) {
throw std::runtime_error("Not enough samples available to be read");
}
uint32_t samples_to_read = std::min(available_samples - offset, total_samples);
if (total_samples == 0) {
samples_to_read = available_samples - offset;
}
fseek(file_handle, static_cast<int32_t>(offset * element_size), SEEK_SET);
samples.resize(samples_to_read);
fread(&samples[0], element_size, samples_to_read, file_handle);
fclose(file_handle);
return samples;
}
double misc_utils::radians_to_hz(const double radians, const double sample_rate) {
return radians * sample_rate / (2 * M_PIf64);
}
double misc_utils::hz_to_radians(const double frequency, const double sample_rate) {
return 2 * M_PIf64 * frequency / sample_rate;
}
std::vector<uint32_t> misc_utils::get_cyclic_prefix_schedule(double sample_rate) {
const auto long_cp_len = get_long_cp_len(sample_rate);
const auto short_cp_len = get_short_cp_len(sample_rate);
return {
long_cp_len,
short_cp_len,
short_cp_len,
short_cp_len,
short_cp_len,
short_cp_len,
short_cp_len,
short_cp_len,
long_cp_len
};
}
std::vector<std::pair<std::vector<std::complex<float>>, std::vector<std::complex<float>>>>
misc_utils::extract_ofdm_symbol_samples(const std::vector<std::complex<float>> & samples, double sample_rate, uint32_t offset) {
std::vector<std::pair<std::vector<std::complex<float>>, std::vector<std::complex<float>>>> outputs(9);
const auto fft_size = get_fft_size(sample_rate);
const auto cyclic_prefixes = get_cyclic_prefix_schedule(sample_rate);
fft::fft_complex_fwd fft_engine(static_cast<int32_t>(fft_size), true);
fft::fft_shift<std::complex<float>> fft_shifter(fft_size);
auto samples_iter = samples.begin() + offset;
for (uint32_t idx = 0; idx < outputs.size(); idx++) {
samples_iter += cyclic_prefixes[idx];
std::vector<std::complex<float>> time_domain(samples_iter, samples_iter + fft_size);
std::vector<std::complex<float>> freq_domain(fft_size);
std::copy(time_domain.begin(), time_domain.end(), fft_engine.get_inbuf());
fft_engine.execute();
std::copy(fft_engine.get_outbuf(), fft_engine.get_outbuf() + fft_size, freq_domain.begin());
fft_shifter.shift(freq_domain);
outputs[idx] = std::make_pair(time_domain, freq_domain);
samples_iter += fft_size;
}
return outputs;
}
std::vector<std::complex<float>>
misc_utils::calculate_channel(const std::vector<std::complex<float>> &symbol, const double sample_rate,
const uint32_t symbol_idx) {
assert(symbol.size() == 600);
std::vector<std::complex<float>> channel(symbol.size(), {0, 0});
const auto fft_size = get_fft_size(sample_rate);
fft::fft_complex_fwd fft_engine(static_cast<int32_t>(fft_size), true);
fft::fft_shift<std::complex<float>> fft_shifter(fft_size);
uint32_t root;
if (symbol_idx == 4) {
root = 600;
} else {
root = 147;
}
auto zc_gold_seq = create_zc_sequence(sample_rate, root);
write_samples_vec("/tmp/zc_time_" + std::to_string(symbol_idx), zc_gold_seq);
std::copy(zc_gold_seq.begin(), zc_gold_seq.end(), fft_engine.get_inbuf());
fft_engine.execute();
std::copy(fft_engine.get_outbuf(), fft_engine.get_outbuf() + fft_size, zc_gold_seq.begin());
fft_shifter.shift(zc_gold_seq);
write_samples_vec("/tmp/zc_freq_" + std::to_string(symbol_idx), zc_gold_seq);
const auto zc_data_only = extract_data_carriers(zc_gold_seq, fft_size);
write_samples_vec("/tmp/zc_data_" + std::to_string(symbol_idx), zc_data_only);
for (uint32_t idx = 0; idx < symbol.size(); idx++) {
channel[idx] = zc_data_only[idx] / symbol[idx];
}
return channel;
}
std::vector<int8_t> misc_utils::qpsk_to_bits(const std::vector<std::complex<float>> &samples) {
std::vector<int8_t> bits(samples.size() * 2);
auto * bit_vec_ptr = &bits[0];
std::for_each(samples.begin(), samples.end(), [&bit_vec_ptr](const gr_complex & sample) {
if (sample.real() > 0 && sample.imag() > 0) {
*bit_vec_ptr++ = 0;
*bit_vec_ptr++ = 0;
} else if (sample.real() > 0 && sample.imag() < 0) {
*bit_vec_ptr++ = 0;
*bit_vec_ptr++ = 1;
} else if (sample.real() < 0 && sample.imag() > 0) {
*bit_vec_ptr++ = 1;
*bit_vec_ptr++ = 0;
} else {
*bit_vec_ptr++ = 1;
*bit_vec_ptr++ = 1;
}
});
uint32_t misc_utils::get_short_cp_len(double sample_rate) {
return static_cast<uint32_t>(round(0.0000046875 * sample_rate));
}
return bits;
}
uint32_t misc_utils::get_fft_size(double sample_rate) {
return static_cast<uint32_t>(round(sample_rate / CARRIER_SPACING));
}
std::vector<std::complex<float>> misc_utils::create_zc_sequence(const double sample_rate, const uint32_t root) {
const auto fft_size = get_fft_size(sample_rate);
std::vector<std::complex<float>> sequence(fft_size, {0, 0});
std::complex<float> misc_utils::mean(const std::complex<float> *const samples, const uint32_t sample_count) {
auto sum = std::accumulate(samples, samples + sample_count, std::complex<float>{0, 0});
return sum / static_cast<float>(sample_count);
}
const uint32_t guard_carriers = fft_size - OCCUPIED_CARRIERS_EXC_DC;
const auto left_guards = guard_carriers / 2;
float misc_utils::var(const std::complex<float> *const samples, uint32_t sample_count) {
const auto mean_val = mean(samples, sample_count);
const auto recip = 1.0f / static_cast<float>(sample_count - 1);
float var_val = 0;
std::vector<std::complex<float>> g (OCCUPIED_CARRIERS_INC_DC);
const auto I = std::complex<double>(0, 1);
for (int idx = 0; idx < OCCUPIED_CARRIERS_INC_DC; idx++) {
// Doing the arith below in double precision and then casting down to a float. Using floats the whole
// way will result in an output that's very far off from the MATLAB implementation. The errors will accumulate
// down the vector
sequence[left_guards + idx] = std::exp(-I * (M_PIf64 * (double)root * (double)idx * (double)(idx + 1) / 601.0));
}
for (uint32_t idx = 0; idx < sample_count; idx++) {
const auto sample = samples[idx] - mean_val;
var_val += (static_cast<float>(std::pow(sample.real(), 2) + std::pow(sample.imag(), 2))) * recip;
}
// Null out the DC carrier
sequence[(fft_size / 2)] = 0;
return var_val;
}
// Create an FFT object that is configured to run an inverse FFT
gr::fft::fft_complex ifft(static_cast<int>(fft_size), false, 1);
float misc_utils::var_no_mean(const std::complex<float> *samples, uint32_t sample_count) {
const auto recip = 1.0f / static_cast<float>(sample_count - 1);
float var_val = 0;
// FFT-shift the inputs (swap the left and right halves) and store in the IFFT input buffer
std::copy(sequence.begin() + (fft_size/2), sequence.begin() + fft_size, ifft.get_inbuf());
std::copy(sequence.begin(), sequence.begin() + (fft_size/2), ifft.get_inbuf() + (fft_size/2));
for (uint32_t idx = 0; idx < sample_count; idx++) {
const auto & sample = samples[idx];
var_val += (static_cast<float>(std::pow(sample.real(), 2) + std::pow(sample.imag(), 2))) * recip;
}
// Run the IFFT
ifft.execute();
return var_val;
}
// Copy the IFFT'd samples out
std::copy(ifft.get_outbuf(), ifft.get_outbuf() + fft_size, sequence.begin());
std::vector<float> misc_utils::abs_squared(const std::vector<std::complex<float>> &samples) {
std::vector<float> ret(samples.size());
// The samples need to be scaled by the FFT size to get the power back down
std::for_each(sequence.begin(), sequence.end(), [fft_size](std::complex<float> & sample){sample /= static_cast<float>(fft_size);});
for (auto idx = decltype(samples.size()){0}; idx < samples.size(); idx++) {
const auto & sample = samples[idx];
ret[idx] = (sample.real() * sample.real()) + (sample.imag() * sample.imag());
}
return sequence;
}
return ret;
}
std::vector<std::complex<float>> misc_utils::conj(const std::vector<std::complex<float>> &input) {
auto vec = input;
std::for_each(vec.begin(), vec.end(), [](std::complex<float> & sample){sample = std::conj(sample);});
return vec;
}
std::vector<std::complex<float>> misc_utils::create_gaussian_noise(const uint32_t sample_count) {
std::vector<std::complex<float>> output(sample_count);
gr::random rand;
for (auto & sample : output) {
sample = rand.rayleigh_complex();
}
void misc_utils::write_samples(const std::string &path, const std::vector<std::complex<float>> &samples) {
write_samples(path, &samples[0], samples.size());
}
return output;
}
void misc_utils::write_samples(const std::string &path, const std::complex<float> * const samples, const uint32_t element_count) {
write(path, samples, sizeof(samples[0]), element_count);
}
std::vector<uint32_t> misc_utils::get_data_carrier_indices(const uint32_t fft_size) {
std::vector<uint32_t> data_carrier_indices(600, 0);
auto * ptr = &data_carrier_indices[0];
for (uint32_t idx = (fft_size / 2) - 300; idx < (fft_size / 2) + 301; idx++) {
if (idx != fft_size / 2) {
*ptr++ = idx;
}
}
return data_carrier_indices;
}
std::vector<std::complex<float>> misc_utils::extract_data_carriers(const std::vector<std::complex<float>> & symbol, const uint32_t fft_size) {
const auto data_carrier_indices = get_data_carrier_indices(fft_size);
std::vector<std::complex<float>> data_carriers(data_carrier_indices.size());
auto iter = data_carriers.begin();
for (const auto & index : data_carrier_indices) {
*iter++ = symbol[index];
}
return data_carriers;
}
void
misc_utils::write(const std::string &path, const void * const elements, const uint32_t element_size, const uint32_t element_count) {
FILE * handle = fopen(path.c_str(), "wb");
if (!handle) {
throw std::runtime_error("Failed to open output file");
}
fwrite(elements, element_size, element_count, handle);
fclose(handle);
}
void misc_utils::write(const std::string &path, const std::vector<uint32_t> &elements) {
write(path, &elements[0], sizeof(elements[0]), elements.size());
}
void misc_utils::print_bits(const std::vector<int8_t> & bits) {
std::ostringstream buff;
for (const auto & bit : bits) {
buff << (bit == 0 ? 0 : 1);
}
buff << "\n";
std::cout << buff.str();
std::flush(std::cout);
}
std::string misc_utils::bit_vec_to_string(const std::vector<int8_t> &bit_vec) {
std::ostringstream buff;
char lut[2] = {'0', '1'};
for (const auto & bit : bit_vec) {
buff << lut[bit];
}
return buff.str();
}
uint32_t
misc_utils::find_zc_seq_start_idx(const std::vector<std::complex<float>> & samples, const double sample_rate) {
const auto fft_size = get_fft_size(sample_rate);
std::vector<float> scores(samples.size() - fft_size);
std::vector<std::complex<float>> window_one(fft_size / 2);
std::vector<std::complex<float>> window_two(fft_size / 2);
auto window_one_iter = samples.begin();
auto window_two_iter = samples.begin() + (fft_size / 2);
std::vector<std::complex<float>> dot_prods(scores.size(), 0);
for (uint32_t idx = 0; idx < scores.size(); idx++) {
std::copy(window_one_iter, window_one_iter + (fft_size / 2), window_one.begin());
std::copy(window_two_iter, window_two_iter + (fft_size / 2), window_two.begin());
window_one_iter++;
window_two_iter++;
std::reverse(window_two.begin(), window_two.end());
for (int i = 0; i < fft_size / 2; i++) {
dot_prods[idx] += window_one[i] * std::conj(window_two[i]);
}
}
volk_32fc_magnitude_squared_32f(&scores[0], &dot_prods[0], dot_prods.size());
gr::droneid::misc_utils::write_samples("/tmp/dots", dot_prods);
gr::droneid::misc_utils::write("/tmp/scores", &scores[0], sizeof(scores[0]), scores.size());
uint32_t max_idx;
volk_32f_index_max_32u(&max_idx, &scores[0], scores.size());
return max_idx;
}
std::vector<std::complex<float>>
misc_utils::read_samples(const std::string &file_path, uint32_t offset, uint32_t total_samples) {
const auto element_size = sizeof(std::complex<float>);
std::vector<std::complex<float>> samples;
FILE * file_handle = fopen(file_path.c_str(), "r");
if (! file_handle) {
throw std::runtime_error("File '" + file_path + "' could not be opened");
}
fseek(file_handle, 0, SEEK_END);
const auto available_samples = static_cast<uint32_t>(static_cast<double>(ftell(file_handle)) / element_size);
if (available_samples < offset) {
throw std::runtime_error("Not enough samples available to be read");
}
uint32_t samples_to_read = std::min(available_samples - offset, total_samples);
if (total_samples == 0) {
samples_to_read = available_samples - offset;
}
fseek(file_handle, static_cast<int32_t>(offset * element_size), SEEK_SET);
samples.resize(samples_to_read);
fread(&samples[0], element_size, samples_to_read, file_handle);
fclose(file_handle);
return samples;
}
double misc_utils::radians_to_hz(const double radians, const double sample_rate) {
return radians * sample_rate / (2 * M_PIf64);
}
double misc_utils::hz_to_radians(const double frequency, const double sample_rate) {
return 2 * M_PIf64 * frequency / sample_rate;
}
std::vector<uint32_t> misc_utils::get_cyclic_prefix_schedule(double sample_rate) {
const auto long_cp_len = get_long_cp_len(sample_rate);
const auto short_cp_len = get_short_cp_len(sample_rate);
return {
long_cp_len,
short_cp_len,
short_cp_len,
short_cp_len,
short_cp_len,
short_cp_len,
short_cp_len,
short_cp_len,
long_cp_len
};
}
std::vector<std::pair<std::vector<std::complex<float>>, std::vector<std::complex<float>>>>
misc_utils::extract_ofdm_symbol_samples(const std::vector<std::complex<float>> & samples, double sample_rate, uint32_t offset) {
std::vector<std::pair<std::vector<std::complex<float>>, std::vector<std::complex<float>>>> outputs(9);
const auto fft_size = get_fft_size(sample_rate);
const auto cyclic_prefixes = get_cyclic_prefix_schedule(sample_rate);
fft::fft_complex fft_engine(static_cast<int32_t>(fft_size), true);
fft::fft_shift<std::complex<float>> fft_shifter(fft_size);
auto samples_iter = samples.begin() + offset;
for (uint32_t idx = 0; idx < outputs.size(); idx++) {
samples_iter += cyclic_prefixes[idx];
std::vector<std::complex<float>> time_domain(samples_iter, samples_iter + fft_size);
std::vector<std::complex<float>> freq_domain(fft_size);
std::copy(time_domain.begin(), time_domain.end(), fft_engine.get_inbuf());
fft_engine.execute();
std::copy(fft_engine.get_outbuf(), fft_engine.get_outbuf() + fft_size, freq_domain.begin());
fft_shifter.shift(freq_domain);
outputs[idx] = std::make_pair(time_domain, freq_domain);
samples_iter += fft_size;
}
return outputs;
}
std::vector<std::complex<float>>
misc_utils::calculate_channel(const std::vector<std::complex<float>> &symbol, const double sample_rate,
const uint32_t symbol_idx) {
assert(symbol.size() == 600);
std::vector<std::complex<float>> channel(symbol.size(), {0, 0});
const auto fft_size = get_fft_size(sample_rate);
fft::fft_complex fft_engine(static_cast<int32_t>(fft_size), true);
fft::fft_shift<std::complex<float>> fft_shifter(fft_size);
uint32_t root;
if (symbol_idx == 4) {
root = 600;
} else {
root = 147;
}
auto zc_gold_seq = create_zc_sequence(sample_rate, root);
write_samples("/tmp/zc_time_" + std::to_string(symbol_idx), zc_gold_seq);
std::copy(zc_gold_seq.begin(), zc_gold_seq.end(), fft_engine.get_inbuf());
fft_engine.execute();
std::copy(fft_engine.get_outbuf(), fft_engine.get_outbuf() + fft_size, zc_gold_seq.begin());
fft_shifter.shift(zc_gold_seq);
write_samples("/tmp/zc_freq_" + std::to_string(symbol_idx), zc_gold_seq);
const auto zc_data_only = extract_data_carriers(zc_gold_seq, fft_size);
write_samples("/tmp/zc_data_" + std::to_string(symbol_idx), zc_data_only);
for (uint32_t idx = 0; idx < symbol.size(); idx++) {
channel[idx] = zc_data_only[idx] / symbol[idx];
}
return channel;
}
std::vector<int8_t> misc_utils::qpsk_to_bits(const std::vector<std::complex<float>> &samples) {
std::vector<int8_t> bits(samples.size() * 2);
auto * bit_vec_ptr = &bits[0];
std::for_each(samples.begin(), samples.end(), [&bit_vec_ptr](const gr_complex & sample) {
if (sample.real() > 0 && sample.imag() > 0) {
*bit_vec_ptr++ = 0;
*bit_vec_ptr++ = 0;
} else if (sample.real() > 0 && sample.imag() < 0) {
*bit_vec_ptr++ = 0;
*bit_vec_ptr++ = 1;
} else if (sample.real() < 0 && sample.imag() > 0) {
*bit_vec_ptr++ = 1;
*bit_vec_ptr++ = 0;
} else {
*bit_vec_ptr++ = 1;
*bit_vec_ptr++ = 1;
}
});
return bits;
}
std::complex<float> misc_utils::mean(const std::vector<std::complex<float>> &samples) {
return mean(&samples[0], samples.size());
}
float misc_utils::var(const std::vector<std::complex<float>> &samples) {
return var(&samples[0], samples.size());
}
std::complex<float> misc_utils::mean(const std::complex<float> *const samples, const uint32_t sample_count) {
auto sum = std::accumulate(samples, samples + sample_count, std::complex<float>{0, 0});
return sum / static_cast<float>(sample_count);
}
float misc_utils::var(const std::complex<float> *const samples, uint32_t sample_count) {
const auto mean_val = mean(samples, sample_count);
const auto recip = 1.0f / static_cast<float>(sample_count - 1);
float var_val = 0;
for (uint32_t idx = 0; idx < sample_count; idx++) {
const auto sample = samples[idx] - mean_val;
var_val += (static_cast<float>(std::pow(sample.real(), 2) + std::pow(sample.imag(), 2))) * recip;
}
return var_val;
}
float misc_utils::var_no_mean(const std::complex<float> *samples, uint32_t sample_count) {
const auto recip = 1.0f / static_cast<float>(sample_count - 1);
float var_val = 0;
for (uint32_t idx = 0; idx < sample_count; idx++) {
const auto & sample = samples[idx];
var_val += (static_cast<float>(std::pow(sample.real(), 2) + std::pow(sample.imag(), 2))) * recip;
}
return var_val;
}
float misc_utils::var_no_mean(const std::vector<std::complex<float>> &samples) {
return var_no_mean(&samples[0], samples.size());
}
std::vector<float> misc_utils::abs_squared(const std::vector<std::complex<float>> &samples) {
std::vector<float> ret(samples.size());
for (auto idx = decltype(samples.size()){0}; idx < samples.size(); idx++) {
const auto & sample = samples[idx];
ret[idx] = (sample.real() * sample.real()) + (sample.imag() * sample.imag());
}
return ret;
}
std::vector<float> misc_utils::abs_squared(const std::vector<std::complex<float>> && samples) {
return abs_squared(samples);
}
std::vector<std::complex<float>> misc_utils::create_gaussian_noise(const uint32_t sample_count) {
std::vector<std::complex<float>> output(sample_count);
gr::random rand;
for (auto & sample : output) {
sample = rand.rayleigh_complex();
}
return output;
}
} /* namespace droneid */
} /* namespace gr */
} /* namespace droneid */
} /* namespace gr */

Wyświetl plik

@ -1,94 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <numeric>
#include <gnuradio/io_signature.h>
#include <droneid/normalized_xcorr.h>
#include <droneid/misc_utils.h>
#include <volk/volk.h>
namespace gr {
namespace droneid {
normalized_xcorr::normalized_xcorr(const complex_vec_t & filter_taps) {
window_size_ = filter_taps.size();
taps_ = (complex_t *)volk_malloc(sizeof(complex_t) * window_size_, volk_get_alignment());
temp_ = (decltype(temp_))volk_malloc(sizeof(temp_[0]) * window_size_, volk_get_alignment());
std::copy(filter_taps.begin(), filter_taps.end(), taps_);
const auto mean = misc_utils::mean(taps_, window_size_);
std::for_each(taps_, taps_ + window_size_, [&mean](complex_t & sample){
sample -= mean;
});
taps_var_ = misc_utils::var(taps_, window_size_);
scalar_ = {1 / static_cast<sample_t>(sqrt(taps_var_) * window_size_), 0};
scores_size_ = 0;
}
normalized_xcorr::~normalized_xcorr() {
if (taps_ != nullptr) {
volk_free(taps_);
}
if (temp_ != nullptr) {
volk_free(temp_);
}
if (scores_ != nullptr) {
volk_free(scores_);
}
};
uint32_t normalized_xcorr::run(const normalized_xcorr::complex_t * const samples, const uint32_t sample_count,
normalized_xcorr::sample_t * const output_samples) {
if (sample_count < window_size_) {
return 0;
}
const auto max_correlations = sample_count - window_size_;
if (scores_size_ < max_correlations) {
if (scores_ != nullptr) {
volk_free(scores_);
}
scores_ = (decltype(scores_))volk_malloc(sizeof(scores_[0]) * max_correlations, volk_get_alignment());
scores_size_ = max_correlations;
}
for (auto offset = decltype(max_correlations){0}; offset < max_correlations; offset++) {
volk_32fc_x2_dot_prod_32fc(&scores_[offset], samples + offset, &taps_[0], window_size_);
}
volk_32fc_s32fc_multiply_32fc_a(&scores_[0], &scores_[0], scalar_, max_correlations);
volk_32fc_magnitude_squared_32f_a(output_samples, &scores_[0], max_correlations);
return max_correlations;
}
} /* namespace droneid */
} /* namespace gr */

Wyświetl plik

@ -1,182 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "normalized_xcorr_estimate_impl.h"
#include <volk/volk.h>
#include <numeric>
#include <droneid/misc_utils.h>
namespace gr {
namespace droneid {
normalized_xcorr_estimate::sptr
normalized_xcorr_estimate::make(const std::vector<gr_complex> &taps) {
return gnuradio::get_initial_sptr
(new normalized_xcorr_estimate_impl(taps));
}
/*
* The private constructor
*/
normalized_xcorr_estimate_impl::normalized_xcorr_estimate_impl(const std::vector<gr_complex> &taps)
: gr::block("dot_prod",
gr::io_signature::make(1, 1, sizeof(gr_complex)),
gr::io_signature::make(1, 1, sizeof(gr_complex))),
taps_(taps), window_size_(taps.size()) {
// Remove the mean from the taps, conjugate the taps, and calculate the variance ahead of time
const auto mean =
std::accumulate(taps_.begin(), taps_.end(), gr_complex{0, 0}) / static_cast<float>(taps_.size());
for (auto & tap : taps_) {
tap = std::conj(tap) - mean;
}
taps_var_ = misc_utils::var_no_mean(taps_);
// Create some constants to enable the use of multiplies instead of divides later
window_size_recip_ = 1.0f / static_cast<float>(window_size_);
window_size_recip_complex_ = gr_complex{window_size_recip_, 0};
}
/*
* Our virtual destructor.
*/
normalized_xcorr_estimate_impl::~normalized_xcorr_estimate_impl() {
}
int
normalized_xcorr_estimate_impl::general_work(int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items) {
// Get handles to the input and output arrays
const auto *in = (const gr_complex *) input_items[0];
auto *out = (gr_complex *) output_items[0];
// Always tell GNU Radio that all samples were accepted even if not this many samples were written out
consume_each(noutput_items);
// This is how the remaining samples are buffered between calls. It's important to realize that this algo
// needs <window_size> samples to be able to produce one output value. This means that there will always
// be unused samples at the end of each function call that need to be held onto until the next call. The
// hope was that set_history() took care of this, but it does not. So, the remaining samples from the last
// call are stored in <buffer_>. The <in> buffer can't hold more samples (it's not known how many samples
// wide the buffer is) so in order to use the old samples without jumping through very slow hoops, the new
// samples are appended to the old samples.
buffer_.insert(buffer_.end(), in, in + noutput_items);
// Exit early if there aren't enough samples to process.
if (buffer_.size() < window_size_) {
return 0;
}
// Figure out how many windows worth of data can be processed. It's possible that this specific call
// doesn't have enough storage in its output buffer to hold all the samples that could be processed. For
// this reason the min of the available output buffer space and number of windows that could be processed
// must be used.
const auto num_steps = std::min(static_cast<uint64_t>(noutput_items), buffer_.size() - window_size_);
// Resize the buffers as needed
if (sums_.size() < num_steps) {
sums_.resize(num_steps);
abs_squared_.resize(num_steps + window_size_);
vars_.resize(num_steps);
}
// TODO(24June2022): There are <window_size-1> extra operations happening on each call. This comes from the
// fact that some of these computations are being done on samples that are going to be
// used again on the next function call. Would be a good idea to buffer the abs squared
// and maybe the running variance average.
// What is happening below is roughly the following:
//
// for idx = 1:length(buffer_) - window_size_
// window = buffer_(idx:idx + window_size_ - 1);
// variance = sum(abs(window).^2) / window_size_;
// dot_prod = sum(window .* taps_) / window_size_;
// out(idx) = dot_prod / sqrt(variance * taps_var_);
// end
//
// But the variance is calculated as a running sum. The first variance has to be calculated the hard way,
// and then every iteration of the loop will subtract off the left-most element of the window that just
// dropped off, and adds on the new right-most element in the window.
//
// Doing this calculation of the first element outside the loop prevents needing a conditional in the
// critical section
// Calculate the first variance the hard way
volk_32fc_magnitude_squared_32f(&abs_squared_[0], &buffer_[0], num_steps + window_size_);
auto running_var = std::accumulate(abs_squared_.begin(), abs_squared_.begin() + window_size_, 0.f);
vars_[0] = running_var;
// Calculate the first dot product
volk_32fc_x2_dot_prod_32fc(&out[0], &buffer_[0], &taps_[0], window_size_);
// Calculate the running abs value sum and dot product for the remaining samples
for (uint32_t idx = 1; idx < num_steps; idx++) {
// sum(abs(window).^2)
running_var = running_var - abs_squared_[idx - 1] + abs_squared_[idx + window_size_];
vars_[idx] = running_var;
// Compute tue dot product of the current window and the filter taps
// sum(window .* taps_)
volk_32fc_x2_dot_prod_32fc(&out[idx], &buffer_[idx], &taps_[0], window_size_);
}
// Scale the dot product down
volk_32fc_s32fc_multiply_32fc(&out[0], &out[0], window_size_recip_complex_, num_steps);
// Scale the variance sums down
volk_32f_s32f_multiply_32f(&vars_[0], &vars_[0], window_size_recip_, num_steps);
// Multiply each variance by the tap variances then take the reciprocal
volk_32f_s32f_multiply_32f(&vars_[0], &vars_[0], taps_var_, num_steps);
// Calculate the inverse square root (1/sqrt(vars_[x]))
volk_32f_invsqrt_32f(&vars_[0], &vars_[0], num_steps);
// Divide by the square root above
volk_32fc_32f_multiply_32fc(&out[0], &out[0], &vars_[0], num_steps);
// Go through all outputs and replace NaN's with zeros. This isn't strictly required, but nice to have
for (uint32_t idx = 0; idx < num_steps; idx++) {
if (out[idx].real() == FP_NAN || out[idx].imag() == FP_NAN) {
out[idx] = zero_complex_;
}
}
// Remove all the samples that have been processed from the buffer. Leaving just the last <window_size_-1>
// samples for the next call
buffer_.erase(buffer_.begin(), buffer_.begin() + num_steps);
// Tell runtime system how many output items we produced.
return num_steps;
}
} /* namespace droneid */
} /* namespace gr */

Wyświetl plik

@ -1,59 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DRONEID_NORMALIZED_XCORR_ESTIMATE_IMPL_H
#define INCLUDED_DRONEID_NORMALIZED_XCORR_ESTIMATE_IMPL_H
#include <droneid/normalized_xcorr_estimate.h>
namespace gr {
namespace droneid {
class normalized_xcorr_estimate_impl : public normalized_xcorr_estimate {
private:
const uint32_t window_size_;
float taps_var_;
float window_size_recip_;
gr_complex window_size_recip_complex_;
std::vector<gr_complex> taps_;
std::vector<gr_complex> sums_;
std::vector<float> vars_;
std::vector<float> abs_squared_;
std::vector<gr_complex> buffer_;
const gr_complex zero_complex_ = gr_complex{0, 0};
// Nothing to declare in this block.
public:
normalized_xcorr_estimate_impl(const std::vector<gr_complex> & taps);
~normalized_xcorr_estimate_impl();
int general_work(int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
};
} // namespace droneid
} // namespace gr
#endif /* INCLUDED_DRONEID_NORMALIZED_XCORR_ESTIMATE_IMPL_H */

Wyświetl plik

@ -1,37 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include <gnuradio/attributes.h>
#include <cppunit/TestAssert.h>
#include "qa_extractor.h"
#include <droneid/extractor.h>
namespace gr {
namespace droneid {
void
qa_extractor::t1()
{
// Put test here
}
} /* namespace droneid */
} /* namespace gr */

Wyświetl plik

@ -1,45 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef _QA_EXTRACTOR_H_
#define _QA_EXTRACTOR_H_
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestCase.h>
namespace gr {
namespace droneid {
class qa_extractor : public CppUnit::TestCase
{
public:
CPPUNIT_TEST_SUITE(qa_extractor);
CPPUNIT_TEST(t1);
CPPUNIT_TEST_SUITE_END();
private:
void t1();
};
} /* namespace droneid */
} /* namespace gr */
#endif /* _QA_EXTRACTOR_H_ */

Wyświetl plik

@ -1,192 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include <gnuradio/attributes.h>
#include <cppunit/TestAssert.h>
#include "qa_normalized_xcorr.h"
#include <droneid/normalized_xcorr.h>
#include <iostream>
#include <boost/test/unit_test.hpp>
#include <gnuradio/random.h>
#include <chrono>
#include <type_traits>
#include <droneid/misc_utils.h>
#include <MatlabEngine.hpp>
#include <MatlabDataArray.hpp>
using namespace matlab::engine;
namespace gr {
namespace droneid {
using sample_t = float;
using complex_t = std::complex<sample_t>;
using complex_vec_t = std::vector<complex_t>;
template <typename OUTPUT_T>
std::vector<OUTPUT_T> run(const std::u16string & cmd, std::vector<matlab::data::Array> & inputs, MATLABEngine * engine) {
std::vector<OUTPUT_T> output;
matlab::data::Array matlab_output = engine->feval(cmd, inputs);
output.resize(matlab_output.getNumberOfElements());
for (uint32_t idx = 0; idx < matlab_output.getNumberOfElements(); idx++) {
output[idx] = static_cast<OUTPUT_T>(matlab_output[idx]);
}
return output;
}
template <typename OUTPUT_T>
std::vector<OUTPUT_T> get_vec(const std::u16string & variable_name, MATLABEngine * const engine_ptr) {
std::vector<OUTPUT_T> output;
auto variable_value = engine_ptr->getVariable(variable_name);
output.reserve(variable_value.getNumberOfElements());
for (const auto & sample : matlab::data::getReadOnlyElements<OUTPUT_T>(variable_value)) {
output.push_back(sample);
}
return output;
}
template <typename OUTPUT_T>
std::vector<std::complex<OUTPUT_T>> get_complex_vec(const std::u16string & variable_name, MATLABEngine * const engine_ptr) {
std::vector<std::complex<OUTPUT_T>> output;
auto variable_value = engine_ptr->getVariable(variable_name);
output.reserve(variable_value.getNumberOfElements());
for (const std::complex<double> & sample : matlab::data::getReadOnlyElements<std::complex<double>>(variable_value)) {
output.push_back({
static_cast<OUTPUT_T>(sample.real()), static_cast<OUTPUT_T>(sample.imag())
});
}
return output;
}
uint64_t get_matrix_length(const std::u16string & variable_name, MATLABEngine * const engine_ptr) {
const auto cmd = u"length(" + variable_name + u");";
engine_ptr->eval(cmd);
const auto ret = engine_ptr->getVariable("ans");
return static_cast<uint64_t>(ret[0]);
}
BOOST_AUTO_TEST_CASE(foo) {
auto matlab_ptr = startMATLAB();
matlab::data::ArrayFactory factory;
gr::random random;
const auto burst = misc_utils::read_samples("/tmp/droneid_debug/burst_25", 0, 0);
const auto full_sample_count = static_cast<uint32_t>(.1e6);
complex_vec_t samples(full_sample_count);
const int64_t padding = floor((static_cast<int64_t>(full_sample_count) - static_cast<int64_t>(burst.size())) / 2);
std::cout << "Padding: " << padding << "\n";
if (padding > 0) {
for (uint64_t idx = 0; idx < padding; idx++) {
samples[idx] = random.rayleigh_complex();
}
std::copy(burst.begin(), burst.end(), samples.begin() + padding);
for (uint64_t idx = padding + burst.size(); idx < samples.size(); idx++) {
samples[idx] = random.rayleigh_complex();
}
} else {
samples = burst;
}
auto filter_taps = misc_utils::create_zc_sequence(15.36e6, 600);
filter_taps.resize(filter_taps.size() / 1);
const auto filter_length = filter_taps.size();
normalized_xcorr xcorr(filter_taps);
std::vector<sample_t> mags(samples.size() - filter_length, 0);
xcorr.run(&samples[0], samples.size(), &mags[0]);
const int iters = 10;
const auto start = std::chrono::high_resolution_clock::now();
for (int iter = 0; iter < iters; iter++) {
xcorr.run(&samples[0], samples.size(), &mags[0]);
}
const auto end = std::chrono::high_resolution_clock::now();
const auto duration = std::chrono::duration<float>(end - start).count();
const auto rate = (samples.size() * iters) / duration;
std::cout << "Took " << duration << " seconds to run through " << samples.size() << " samples\n";
std::cout << "Average of " << rate << " samples per second\n";
const auto max_element_iter = std::max_element(mags.begin(), mags.end());
const auto distance = std::distance(mags.begin(), max_element_iter);
std::cout << "c++ Distance: " << distance << "\n";
complex_vec_t matlab_golden_mags;
{
auto samples_vec = factory.createArray<complex_t>(
matlab::data::ArrayDimensions({samples.size(), 1}),
&samples[0],
&samples[samples.size() - 1]);
auto filter_taps_vec = factory.createArray<complex_t>(
matlab::data::ArrayDimensions({filter_taps.size(), 1}),
&filter_taps[0],
&filter_taps[filter_taps.size() - 1]);
matlab_ptr->setVariable("samples", samples_vec);
matlab_ptr->setVariable("filter", filter_taps_vec);
const std::u16string correlation_script =
u"scores1 = zeros(length(samples) - length(filter), 1);\n"
u"scores2 = zeros(length(samples) - length(filter), 1);\n"
u"for idx = 1:length(scores1)\n"
u" window = samples(idx:idx + length(filter) - 1);"
u" scores1(idx) = xcorr(window, filter, 'normalized', 0);"
u" scores2(idx) = sum(window .* conj(filter)) / length(filter);"
u"end";
matlab_ptr->eval(correlation_script);
matlab_golden_mags = get_complex_vec<sample_t>(u"scores1", matlab_ptr.get());
std::cout << "Got back " << matlab_golden_mags.size() << " correlation scores\n";
}
const auto matlab_golden_mags_sqrd = misc_utils::abs_squared(matlab_golden_mags);
matlab_ptr->setVariable(u"cpp_mags", factory.createArray<sample_t>(
matlab::data::ArrayDimensions({mags.size(), 1}), &mags[0], &mags[mags.size() - 1]));
matlab_ptr->eval(u"delta = cpp_mags - (abs(scores1).^2);");
const auto deltas = get_vec<sample_t>(u"delta", matlab_ptr.get());
matlab_ptr->eval(u"figure(1); plot(delta);");
matlab_ptr->eval(u"figure(2); subplot(3, 1, 1); plot(abs(cpp_mags)); title('CPP mags');");
matlab_ptr->eval(u"figure(2); subplot(3, 1, 2); plot(abs(scores1).^2); title('MATLAB mags');");
matlab_ptr->eval(u"figure(2); subplot(3, 1, 3); plot(10 * log10(abs(samples).^2)); title('Raw Samples');");
matlab_ptr->eval(u"pause;");
}
} /* namespace droneid */
} /* namespace gr */

Wyświetl plik

@ -1,44 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef _QA_NORMALIZED_XCORR_H_
#define _QA_NORMALIZED_XCORR_H_
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestCase.h>
namespace gr {
namespace droneid {
class qa_normalized_xcorr : public CppUnit::TestCase {
public:
CPPUNIT_TEST_SUITE(qa_normalized_xcorr);
CPPUNIT_TEST(t1);
CPPUNIT_TEST_SUITE_END();
private:
void t1();
};
} /* namespace droneid */
} /* namespace gr */
#endif /* _QA_NORMALIZED_XCORR_H_ */

Wyświetl plik

@ -1,60 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include <iostream>
#include <gnuradio/attributes.h>
#include "qa_normalized_xcorr_estimate.h"
#include <droneid/normalized_xcorr_estimate.h>
#include <droneid/misc_utils.h>
#include <boost/test/unit_test.hpp>
#include <gnuradio/blocks/vector_source.h>
#include <gnuradio/blocks/vector_sink.h>
#include <gnuradio/blocks/file_source.h>
#include <gnuradio/top_block.h>
namespace gr {
namespace droneid {
BOOST_AUTO_TEST_CASE(normalized_xcorr_estimate_test) {
auto tb = gr::make_top_block("top");
const auto noise = misc_utils::create_gaussian_noise(12000);
const auto taps_offset = 4562;
const auto taps_size = 1024;
const auto taps = std::vector<gr_complex>(noise.begin() + taps_offset, noise.begin() + taps_offset + taps_size);
auto source = gr::blocks::vector_source<gr_complex>::make(noise);
auto sink = gr::blocks::vector_sink<gr_complex>::make();
auto uut = droneid::normalized_xcorr_estimate::make(taps);
tb->connect(source, 0, uut, 0);
tb->connect(uut, 0, sink, 0);
tb->run();
std::cout << "Sent in " << noise.size() << " samples, got back " << sink->data().size() << " samples\n";
}
} /* namespace droneid */
} /* namespace gr */

Wyświetl plik

@ -1,45 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef _QA_NORMALIZED_XCORR_ESTIMATE_H_
#define _QA_NORMALIZED_XCORR_ESTIMATE_H_
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestCase.h>
namespace gr {
namespace droneid {
class qa_normalized_xcorr_estimate : public CppUnit::TestCase
{
public:
CPPUNIT_TEST_SUITE(qa_normalized_xcorr_estimate);
CPPUNIT_TEST(t1);
CPPUNIT_TEST_SUITE_END();
private:
void t1();
};
} /* namespace droneid */
} /* namespace gr */
#endif /* _QA_NORMALIZED_XCORR_ESTIMATE_H_ */

Wyświetl plik

@ -1,142 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include <gnuradio/attributes.h>
#include <cppunit/TestAssert.h>
#include "qa_variance.h"
#include <droneid/variance.h>
#include <boost/test/unit_test.hpp>
#include <gnuradio/blocks/vector_source.h>
#include <gnuradio/blocks/vector_sink.h>
#include <gnuradio/top_block.h>
#include <gnuradio/random.h>
#include <MatlabEngine.hpp>
#include <MatlabDataArray.hpp>
namespace gr {
namespace droneid {
std::vector<gr_complex> create_noise(const uint32_t sample_count) {
std::vector<gr_complex> samples(sample_count);
gr::random rng;
for (auto & sample : samples) {
sample = rng.rayleigh_complex();
}
return samples;
}
std::vector<float> calculate_true_variance(const std::vector<gr_complex> & samples, const uint32_t window_size) {
using namespace matlab::engine;
using namespace matlab::data;
ArrayFactory factory;
auto matlab = startMATLAB();
auto samples_matlab = factory.createArray<gr_complex>(
ArrayDimensions({samples.size(), 1}), &samples[0], &samples[samples.size() - 1]);
matlab->setVariable("samples", samples_matlab);
matlab->setVariable("window_size", factory.createScalar(window_size));
const auto program =
u"scores = zeros(length(samples) - window_size, 1);"
u"for idx = 1:length(scores)"
u" window = samples(idx:idx + window_size - 1);"
u" scores(idx) = var(window);"
u"end";
matlab->eval(program);
const auto scores = matlab->getVariable("scores");
std::vector<float> output(scores.getNumberOfElements());
for (uint32_t idx = 0; idx < output.size(); idx++) {
output[idx] = static_cast<float>(scores[idx]);
}
return output;
}
void plot_results(const std::vector<float> & expected_values, const std::vector<float> & uut_output,
const uint32_t window_size) {
auto matlab = matlab::engine::startMATLAB();
matlab::data::ArrayFactory factory;
const auto matlab_values = factory.createArray<float>(
matlab::data::ArrayDimensions({expected_values.size(), 1}),
&expected_values[0], &expected_values[expected_values.size() - 1]);
const auto uut_values = factory.createArray<float>(
matlab::data::ArrayDimensions({uut_output.size(), 1}),
&uut_output[0], &uut_output[uut_output.size() - 1]);
matlab->setVariable("matlab", matlab_values);
matlab->setVariable("uut", uut_values);
matlab->setVariable("window_size", factory.createScalar(window_size));
matlab->eval(
u"figure(1);"
u"subplot(3, 1, 1); plot(matlab); title('MATLAB');"
u"subplot(3, 1, 2); plot(uut); title('UUT');"
u"subplot(3, 1, 3); plot(uut - matlab); title('Delta');"
u"pause");
}
BOOST_AUTO_TEST_CASE(test_variance) {
const float max_delta = 60e-3;
auto tb = gr::make_top_block("top");
const auto sample_count = 12000;
const auto window_size = 1024;
const auto noise = create_noise(sample_count);
auto source = gr::blocks::vector_source<gr_complex>::make(noise);
auto sink = gr::blocks::vector_sink<float>::make();
auto uut = gr::droneid::variance::make(window_size);
tb->connect(source, 0, uut, 0);
tb->connect(uut, 0, sink, 0);
tb->run();
const auto expected_values = calculate_true_variance(noise, window_size);
const auto & uut_output = sink->data();
for (uint32_t idx = 0; idx < expected_values.size(); idx++) {
const auto delta = abs(expected_values[idx] - uut_output[idx]);
BOOST_ASSERT(delta < max_delta);
}
BOOST_ASSERT_MSG(expected_values.size() == uut_output.size(),
"Did not get expected number of samples back");
plot_results(expected_values, uut_output, window_size);
}
} /* namespace droneid */
} /* namespace gr */

Wyświetl plik

@ -1,45 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef _QA_VARIANCE_H_
#define _QA_VARIANCE_H_
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestCase.h>
namespace gr {
namespace droneid {
class qa_variance : public CppUnit::TestCase
{
public:
CPPUNIT_TEST_SUITE(qa_variance);
CPPUNIT_TEST(t1);
CPPUNIT_TEST_SUITE_END();
private:
void t1();
};
} /* namespace droneid */
} /* namespace gr */
#endif /* _QA_VARIANCE_H_ */

Wyświetl plik

@ -1,116 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <boost/filesystem.hpp>
#include <gnuradio/io_signature.h>
#include "time_sync_impl.h"
#include <volk/volk.h>
#include "droneid/misc_utils.h"
#include <gnuradio/filter/fir_filter.h>
namespace gr {
namespace droneid {
using path = boost::filesystem::path;
time_sync::sptr
time_sync::make(double sample_rate, const std::string & debug_path) {
return gnuradio::get_initial_sptr
(new time_sync_impl(sample_rate, debug_path));
}
/*
* The private constructor
*/
time_sync_impl::time_sync_impl(double sample_rate, const std::string & debug_path)
: gr::sync_block("time_sync",
gr::io_signature::make(0, 0, 0),
gr::io_signature::make(0, 0, 0)),
sample_rate_(sample_rate),
fft_size_(misc_utils::get_fft_size(sample_rate)), long_cp_len_(misc_utils::get_long_cp_len(sample_rate)),
short_cp_len_(misc_utils::get_short_cp_len(sample_rate)), debug_path_(debug_path) {
if (! debug_path_.empty()) {
const auto p = path(debug_path_);
if (! boost::filesystem::is_directory(p)) {
boost::filesystem::create_directories(p);
}
}
auto zc_sequence = misc_utils::create_zc_sequence(sample_rate_, 600);
std::for_each(zc_sequence.begin(), zc_sequence.end(), [](std::complex<float> & sample){ sample = std::conj(sample); });
std::reverse(zc_sequence.begin(), zc_sequence.end());
correlator_ptr_ = std::unique_ptr<filter_t>(new filter_t(1, zc_sequence));
message_port_register_in(pmt::mp("pdus"));
message_port_register_out(pmt::mp("pdus"));
set_msg_handler(pmt::mp("pdus"), [this](pmt::pmt_t pdu) { this->msg_handler(pdu); });
}
/*
* Our virtual destructor.
*/
time_sync_impl::~time_sync_impl() {
}
void time_sync_impl::msg_handler(const pmt::pmt_t & pdu) {
auto meta = pmt::car(pdu);
auto vec = pmt::cdr(pdu);
const auto samples = pmt::c32vector_elements(vec);
if (! debug_path_.empty()) {
misc_utils::write_samples((path(debug_path_) / std::to_string(file_counter_++)).string(), samples);
}
if (buffer_.size() < samples.size()) {
buffer_.resize(samples.size());
mags_.resize(samples.size());
}
const auto max_idx = misc_utils::find_zc_seq_start_idx(samples, sample_rate_);
const uint32_t offset = (fft_size_ * 3) + (short_cp_len_ * 3) + long_cp_len_;
std::cout << "Max: " << max_idx << " offset: " << offset << " - " << (max_idx - offset) << "\n";
std::cout << "short: " << short_cp_len_ << " long: " << long_cp_len_ << " fft: " << fft_size_ << "\n";
auto new_meta = pmt::make_dict();
new_meta = pmt::dict_add(new_meta, pmt::mp("start_idx"), pmt::from_uint64(max_idx - offset));
pmt::print(new_meta);
message_port_pub(pmt::mp("pdus"), pmt::cons(new_meta, vec));
file_counter_++;
}
int
time_sync_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items) {
// Tell runtime system how many output items we produced.
return noutput_items;
}
} /* namespace droneid */
} /* namespace gr */

Wyświetl plik

@ -1,64 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DRONEID_TIME_SYNC_IMPL_H
#define INCLUDED_DRONEID_TIME_SYNC_IMPL_H
#include <droneid/time_sync.h>
#include <gnuradio/filter/fir_filter.h>
namespace gr {
namespace droneid {
class time_sync_impl : public time_sync {
private:
using filter_t = gr::filter::kernel::fir_filter_ccc;
const double sample_rate_;
const uint32_t fft_size_;
const uint32_t long_cp_len_;
const uint32_t short_cp_len_;
const std::string debug_path_;
size_t pdu_element_count_;
std::vector<std::complex<float>> buffer_;
std::vector<float> mags_;
std::unique_ptr<filter_t> correlator_ptr_;
uint32_t file_counter_ = 0;
void msg_handler(const pmt::pmt_t & pdu);
public:
time_sync_impl(double sample_rate, const std::string & debug_path);
~time_sync_impl();
// Where all the action really happens
int work(
int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items
);
};
} // namespace droneid
} // namespace gr
#endif /* INCLUDED_DRONEID_TIME_SYNC_IMPL_H */

Wyświetl plik

@ -1,56 +0,0 @@
//
// Created by main on 4/20/22.
//
#include "utils.h"
#include <gnuradio/filter/fft_filter.h>
uint32_t get_long_cp_len(double sample_rate) {
return static_cast<uint32_t>(std::round(sample_rate / 192000));
}
uint32_t get_short_cp_len(double sample_rate) {
return static_cast<uint32_t>(round(0.0000046875 * sample_rate));
}
uint32_t get_fft_size(double sample_rate) {
return static_cast<uint32_t>(round(sample_rate / CARRIER_SPACING));
}
std::vector<std::complex<float>> create_zc_sequence(const double sample_rate, const uint32_t root) {
const auto fft_size = get_fft_size(sample_rate);
std::vector<std::complex<float>> sequence(fft_size, {0, 0});
const uint32_t guard_carriers = fft_size - OCCUPIED_CARRIERS_EXC_DC;
const auto left_guards = guard_carriers / 2;
std::vector<std::complex<float>> g (OCCUPIED_CARRIERS_INC_DC);
const auto I = std::complex<double>(0, 1);
for (int idx = 0; idx < OCCUPIED_CARRIERS_INC_DC; idx++) {
// Doing the arith below in double precision and then casting down to a float. Using floats the whole
// way will result in an output that's very far off from the MATLAB implementation. The errors will accumulate
// down the vector
sequence[left_guards + idx] = std::exp(-I * (M_PIf64 * (double)root * (double)idx * (double)(idx + 1) / 601.0));
}
// Null out the DC carrier
sequence[(fft_size / 2) - 1] = 0;
// Create an FFT object that is configured to run an inverse FFT
gr::fft::fft_complex ifft(static_cast<int>(fft_size), false, 1);
// FFT-shift the inputs (swap the left and right halves) and store in the IFFT input buffer
std::copy(sequence.begin() + (fft_size/2), sequence.begin() + fft_size, ifft.get_inbuf());
std::copy(sequence.begin(), sequence.begin() + (fft_size/2), ifft.get_inbuf() + (fft_size/2));
// Run the IFFT
ifft.execute();
// Copy the IFFT'd samples out
std::copy(ifft.get_outbuf(), ifft.get_outbuf() + fft_size, sequence.begin());
// The samples need to be scaled by the FFT size to get the power back down
std::for_each(sequence.begin(), sequence.end(), [fft_size](std::complex<float> & sample){sample /= static_cast<float>(fft_size);});
return sequence;
}

Wyświetl plik

@ -1,22 +0,0 @@
//
// Created by main on 4/20/22.
//
#ifndef GR_DRONEID_UTILS_H
#define GR_DRONEID_UTILS_H
#include <cstdint>
#include <vector>
#include <complex>
static constexpr double CARRIER_SPACING = 15e3;
static constexpr uint32_t OCCUPIED_CARRIERS_EXC_DC = 600;
static constexpr uint32_t OCCUPIED_CARRIERS_INC_DC = 601;
uint32_t get_long_cp_len(double sample_rate);
uint32_t get_short_cp_len(double sample_rate);
uint32_t get_fft_size(double sample_rate);
std::vector<std::complex<float>> create_zc_sequence(double sample_rate, uint32_t root);
#endif //GR_DRONEID_UTILS_H

Wyświetl plik

@ -1,96 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "variance_impl.h"
#include <volk/volk.h>
namespace gr {
namespace droneid {
variance::sptr
variance::make(uint32_t window_size) {
return gnuradio::get_initial_sptr
(new variance_impl(window_size));
}
/*
* The private constructor
*/
variance_impl::variance_impl(uint32_t window_size)
: gr::block("variance",
gr::io_signature::make(1, 1, sizeof(gr_complex)),
gr::io_signature::make(1, 1, sizeof(float))),
window_size_(window_size),
window_size_recip_(1.0f / static_cast<float>(window_size)) {
}
/*
* Our virtual destructor.
*/
variance_impl::~variance_impl() {
}
int variance_impl::general_work(int noutput_items, gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) {
const auto * in = (gr_complex *) input_items[0];
auto * out = (float *) output_items[0];
buffer_.insert(buffer_.end(), in, in + noutput_items);
if (buffer_.size() < window_size_) {
consume_each(noutput_items);
return 0;
}
const auto num_steps = buffer_.size() - window_size_;
if (abs_squared_.size() < buffer_.size()) {
abs_squared_.resize(buffer_.size());
sum_.resize(num_steps);
}
volk_32fc_magnitude_squared_32f(&abs_squared_[0], &buffer_[0], buffer_.size());
float running_sum;
volk_32f_accumulator_s32f_a(&running_sum, &abs_squared_[0], window_size_);
sum_[0] = running_sum;
for (uint32_t idx = 1; idx < num_steps; idx++) {
running_sum = running_sum - abs_squared_[idx - 1] + abs_squared_[idx + window_size_];
sum_[idx] = running_sum;
}
volk_32f_s32f_multiply_32f(out, &sum_[0], window_size_recip_, num_steps);
buffer_.erase(buffer_.begin(), buffer_.begin() + num_steps);
consume_each(noutput_items);
return num_steps;
}
} /* namespace droneid */
} /* namespace gr */

Wyświetl plik

@ -1,52 +0,0 @@
/* -*- c++ -*- */
/*
* Copyright 2022 gr-droneid author.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_DRONEID_VARIANCE_IMPL_H
#define INCLUDED_DRONEID_VARIANCE_IMPL_H
#include <droneid/variance.h>
namespace gr {
namespace droneid {
class variance_impl : public variance {
private:
const uint32_t window_size_;
const float window_size_recip_;
std::vector<gr_complex> buffer_;
std::vector<float> abs_squared_;
std::vector<float> sum_;
public:
variance_impl(uint32_t window_size);
~variance_impl();
int general_work(int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items) override;
};
} // namespace droneid
} // namespace gr
#endif /* INCLUDED_DRONEID_VARIANCE_IMPL_H */

Wyświetl plik

@ -1,49 +0,0 @@
# Copyright 2011 Free Software Foundation, Inc.
#
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-droneid
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
########################################################################
# Include python install macros
########################################################################
include(GrPython)
if(NOT PYTHONINTERP_FOUND)
return()
endif()
########################################################################
# Install python sources
########################################################################
GR_PYTHON_INSTALL(
FILES
__init__.py
DESTINATION ${GR_PYTHON_DIR}/droneid
)
########################################################################
# Handle the unit tests
########################################################################
include(GrTest)
set(GR_TEST_TARGET_DEPS gnuradio-droneid)
set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig)
GR_ADD_TEST(qa_extractor ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_extractor.py)
GR_ADD_TEST(qa_time_sync ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_time_sync.py)
GR_ADD_TEST(qa_demodulation ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_demodulation.py)
GR_ADD_TEST(qa_normalized_xcorr_estimate ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_normalized_xcorr_estimate.py)
GR_ADD_TEST(qa_variance ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_variance.py)

Wyświetl plik

@ -1,37 +0,0 @@
#
# Copyright 2008,2009 Free Software Foundation, Inc.
#
# This application is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# This application is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# The presence of this file turns this directory into a Python package
'''
This is the GNU Radio DRONEID module. Place your Python package
description here (python/__init__.py).
'''
from __future__ import unicode_literals
# import swig generated symbols into the droneid namespace
try:
# this might fail if the module is python-only
from .droneid_swig import *
except ImportError:
import traceback
traceback.print_exc()
pass
# import any pure python here
#

Wyświetl plik

@ -0,0 +1,5 @@
*~
*.pyc
*.pyo
build*/
examples/grc/*.py

Wyświetl plik

@ -0,0 +1,41 @@
# Copyright 2011 Free Software Foundation, Inc.
#
# This file was generated by gr_modtool, a tool from the GNU Radio framework
# This file is a part of gr-droneid
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
########################################################################
# Include python install macros
########################################################################
include(GrPython)
if(NOT PYTHONINTERP_FOUND)
return()
endif()
add_subdirectory(bindings)
########################################################################
# Install python sources
########################################################################
GR_PYTHON_INSTALL(
FILES
__init__.py
DESTINATION ${GR_PYTHON_DIR}/gnuradio/droneid
)
########################################################################
# Handle the unit tests
########################################################################
include(GrTest)
set(GR_TEST_TARGET_DEPS gnuradio-droneid)
# Create a package directory that tests can import. It includes everything
# from `python/`.
add_custom_target(
copy_module_for_tests ALL
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}
${PROJECT_BINARY_DIR}/test_modules/gnuradio/droneid/
)

Wyświetl plik

@ -0,0 +1,23 @@
#
# Copyright 2008,2009 Free Software Foundation, Inc.
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# The presence of this file turns this directory into a Python package
'''
This is the GNU Radio DRONEID module. Place your Python package
description here (python/__init__.py).
'''
import os
# import pybind11 generated symbols into the droneid namespace
try:
# this might fail if the module is python-only
from .droneid_python import *
except ModuleNotFoundError:
pass
# import any pure python here
#

Wyświetl plik

@ -0,0 +1,45 @@
# Copyright 2020 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
########################################################################
# Check if there is C++ code at all
########################################################################
if(NOT droneid_sources)
MESSAGE(STATUS "No C++ sources... skipping python bindings")
return()
endif(NOT droneid_sources)
########################################################################
# Check for pygccxml
########################################################################
GR_PYTHON_CHECK_MODULE_RAW(
"pygccxml"
"import pygccxml"
PYGCCXML_FOUND
)
include(GrPybind)
########################################################################
# Python Bindings
########################################################################
list(APPEND droneid_python_files
misc_utils_python.cc python_bindings.cc)
GR_PYBIND_MAKE_OOT(droneid
../../..
gr::droneid
"${droneid_python_files}")
# copy bindings extension for use in QA test module
add_custom_command(TARGET droneid_python POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:droneid_python>
${PROJECT_BINARY_DIR}/test_modules/gnuradio/droneid/
)
install(TARGETS droneid_python DESTINATION ${GR_PYTHON_DIR}/gnuradio/droneid COMPONENT pythonapi)

Wyświetl plik

@ -0,0 +1,54 @@
import warnings
import argparse
from gnuradio.bindtool import BindingGenerator
import sys
import tempfile
parser = argparse.ArgumentParser(description='Bind a GR Out of Tree Block')
parser.add_argument('--module', type=str,
help='Name of gr module containing file to bind (e.g. fft digital analog)')
parser.add_argument('--output_dir', default=tempfile.gettempdir(),
help='Output directory of generated bindings')
parser.add_argument('--prefix', help='Prefix of Installed GNU Radio')
parser.add_argument(
'--filename', help="File to be parsed")
parser.add_argument(
'--defines', help='Set additional defines for precompiler', default=(), nargs='*')
parser.add_argument(
'--include', help='Additional Include Dirs, separated', default=(), nargs='*')
parser.add_argument(
'--status', help='Location of output file for general status (used during cmake)', default=None
)
parser.add_argument(
'--flag_automatic', default='0'
)
parser.add_argument(
'--flag_pygccxml', default='0'
)
args = parser.parse_args()
prefix = args.prefix
output_dir = args.output_dir
defines = tuple(','.join(args.defines).split(','))
includes = ','.join(args.include)
name = args.module
namespace = ['gr', name]
prefix_include_root = name
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
bg = BindingGenerator(prefix, namespace,
prefix_include_root, output_dir, define_symbols=defines, addl_includes=includes,
catch_exceptions=False, write_json_output=False, status_output=args.status,
flag_automatic=True if args.flag_automatic.lower() in [
'1', 'true'] else False,
flag_pygccxml=True if args.flag_pygccxml.lower() in ['1', 'true'] else False)
bg.gen_file_binding(args.filename)

Wyświetl plik

@ -0,0 +1 @@
This directory stores templates for docstrings that are scraped from the include header files for each block

Wyświetl plik

@ -0,0 +1,105 @@
/*
* Copyright 2022 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
*/
#include "pydoc_macros.h"
#define D(...) DOC(gr, droneid, __VA_ARGS__)
/*
This file contains placeholders for docstrings for the Python bindings.
Do not edit! These were automatically extracted during the binding process
and will be overwritten during the build process
*/
static const char* __doc_gr_droneid_misc_utils = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_misc_utils_0 = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_misc_utils_1 = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_get_long_cp_len = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_get_short_cp_len = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_get_fft_size = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_create_gaussian_noise = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_create_zc_sequence = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_conj = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_mean = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_var = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_var_no_mean = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_write = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_write_vec = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_write_samples = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_write_samples_vec = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_read_samples = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_get_data_carrier_indices = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_extract_data_carriers = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_bit_vec_to_string = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_print_bits = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_find_zc_seq_start_idx = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_radians_to_hz = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_hz_to_radians = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_get_cyclic_prefix_schedule = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_extract_ofdm_symbol_samples = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_calculate_channel = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_qpsk_to_bits = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_angle = R"doc()doc";
static const char* __doc_gr_droneid_misc_utils_abs_squared = R"doc()doc";

Wyświetl plik

@ -0,0 +1,80 @@
# Utilities for reading values in header files
from argparse import ArgumentParser
import re
class PybindHeaderParser:
def __init__(self, pathname):
with open(pathname, 'r') as f:
self.file_txt = f.read()
def get_flag_automatic(self):
# p = re.compile(r'BINDTOOL_GEN_AUTOMATIC\(([^\s])\)')
# m = p.search(self.file_txt)
m = re.search(r'BINDTOOL_GEN_AUTOMATIC\(([^\s])\)', self.file_txt)
if (m and m.group(1) == '1'):
return True
else:
return False
def get_flag_pygccxml(self):
# p = re.compile(r'BINDTOOL_USE_PYGCCXML\(([^\s])\)')
# m = p.search(self.file_txt)
m = re.search(r'BINDTOOL_USE_PYGCCXML\(([^\s])\)', self.file_txt)
if (m and m.group(1) == '1'):
return True
else:
return False
def get_header_filename(self):
# p = re.compile(r'BINDTOOL_HEADER_FILE\(([^\s]*)\)')
# m = p.search(self.file_txt)
m = re.search(r'BINDTOOL_HEADER_FILE\(([^\s]*)\)', self.file_txt)
if (m):
return m.group(1)
else:
return None
def get_header_file_hash(self):
# p = re.compile(r'BINDTOOL_HEADER_FILE_HASH\(([^\s]*)\)')
# m = p.search(self.file_txt)
m = re.search(r'BINDTOOL_HEADER_FILE_HASH\(([^\s]*)\)', self.file_txt)
if (m):
return m.group(1)
else:
return None
def get_flags(self):
return f'{self.get_flag_automatic()};{self.get_flag_pygccxml()};{self.get_header_filename()};{self.get_header_file_hash()};'
def argParse():
"""Parses commandline args."""
desc = 'Reads the parameters from the comment block in the pybind files'
parser = ArgumentParser(description=desc)
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"])
parser.add_argument(
"pathname", help="Pathname of pybind c++ file to read, e.g. blockname_python.cc")
return parser.parse_args()
if __name__ == "__main__":
# Parse command line options and set up doxyxml.
args = argParse()
pbhp = PybindHeaderParser(args.pathname)
if args.function == "flag_auto":
print(pbhp.get_flag_automatic())
elif args.function == "flag_pygccxml":
print(pbhp.get_flag_pygccxml())
elif args.function == "header_filename":
print(pbhp.get_header_filename())
elif args.function == "header_file_hash":
print(pbhp.get_header_file_hash())
elif args.function == "all":
print(pbhp.get_flags())

Wyświetl plik

@ -0,0 +1,221 @@
/*
* Copyright 2022 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
*/
/***********************************************************************************/
/* This file is automatically generated using bindtool and can be manually edited */
/* The following lines can be configured to regenerate this file during cmake */
/* If manual edits are made, the following tags should be modified accordingly. */
/* BINDTOOL_GEN_AUTOMATIC(0) */
/* BINDTOOL_USE_PYGCCXML(0) */
/* BINDTOOL_HEADER_FILE(misc_utils.h) */
/* BINDTOOL_HEADER_FILE_HASH(e0008732316f57a487227b92a5f8ecbb) */
/***********************************************************************************/
#include <pybind11/complex.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
namespace py = pybind11;
#include <gnuradio/droneid/misc_utils.h>
// pydoc.h is automatically generated in the build directory
#include <misc_utils_pydoc.h>
void bind_misc_utils(py::module& m)
{
using misc_utils = ::gr::droneid::misc_utils;
py::class_<misc_utils, std::shared_ptr<misc_utils>>(m, "misc_utils", D(misc_utils))
.def(py::init<>(), D(misc_utils, misc_utils, 0))
.def(py::init<gr::droneid::misc_utils const&>(),
py::arg("arg0"),
D(misc_utils, misc_utils, 1))
.def_static("get_long_cp_len",
&misc_utils::get_long_cp_len,
py::arg("sample_rate"),
D(misc_utils, get_long_cp_len))
.def_static("get_short_cp_len",
&misc_utils::get_short_cp_len,
py::arg("sample_rate"),
D(misc_utils, get_short_cp_len))
.def_static("get_fft_size",
&misc_utils::get_fft_size,
py::arg("sample_rate"),
D(misc_utils, get_fft_size))
.def_static("create_gaussian_noise",
&misc_utils::create_gaussian_noise,
py::arg("sample_count"),
D(misc_utils, create_gaussian_noise))
.def_static("create_zc_sequence",
&misc_utils::create_zc_sequence,
py::arg("sample_rate"),
py::arg("root"),
D(misc_utils, create_zc_sequence))
.def_static("conj", &misc_utils::conj, py::arg("input"), D(misc_utils, conj))
.def_static("mean",
&misc_utils::mean,
py::arg("samples"),
py::arg("sample_count"),
D(misc_utils, mean))
.def_static("var",
&misc_utils::var,
py::arg("samples"),
py::arg("sample_count"),
D(misc_utils, var))
.def_static("var_no_mean",
&misc_utils::var_no_mean,
py::arg("samples"),
py::arg("sample_count"),
D(misc_utils, var_no_mean))
.def_static("write",
&misc_utils::write,
py::arg("path"),
py::arg("element"),
py::arg("element_size"),
py::arg("element_count"),
D(misc_utils, write))
.def_static("write_vec",
&misc_utils::write_vec,
py::arg("path"),
py::arg("elements"),
D(misc_utils, write_vec))
.def_static("write_samples",
&misc_utils::write_samples,
py::arg("path"),
py::arg("samples"),
py::arg("element_count"),
D(misc_utils, write_samples))
.def_static("write_samples_vec",
&misc_utils::write_samples_vec,
py::arg("path"),
py::arg("samples"),
D(misc_utils, write_samples_vec))
.def_static("read_samples",
&misc_utils::read_samples,
py::arg("file_path"),
py::arg("offset"),
py::arg("total_samples"),
D(misc_utils, read_samples))
.def_static("get_data_carrier_indices",
&misc_utils::get_data_carrier_indices,
py::arg("fft_size"),
D(misc_utils, get_data_carrier_indices))
.def_static("extract_data_carriers",
&misc_utils::extract_data_carriers,
py::arg("symbol"),
py::arg("fft_size"),
D(misc_utils, extract_data_carriers))
.def_static("bit_vec_to_string",
&misc_utils::bit_vec_to_string,
py::arg("bit_vec"),
D(misc_utils, bit_vec_to_string))
.def_static("print_bits",
&misc_utils::print_bits,
py::arg("bits"),
D(misc_utils, print_bits))
.def_static("find_zc_seq_start_idx",
&misc_utils::find_zc_seq_start_idx,
py::arg("samples"),
py::arg("sample_rate"),
D(misc_utils, find_zc_seq_start_idx))
.def_static("radians_to_hz",
&misc_utils::radians_to_hz,
py::arg("radians"),
py::arg("sample_rate"),
D(misc_utils, radians_to_hz))
.def_static("hz_to_radians",
&misc_utils::hz_to_radians,
py::arg("frequency"),
py::arg("sample_rate"),
D(misc_utils, hz_to_radians))
.def_static("get_cyclic_prefix_schedule",
&misc_utils::get_cyclic_prefix_schedule,
py::arg("sample_rate"),
D(misc_utils, get_cyclic_prefix_schedule))
.def_static("extract_ofdm_symbol_samples",
&misc_utils::extract_ofdm_symbol_samples,
py::arg("samples"),
py::arg("sample_rate"),
py::arg("offset"),
D(misc_utils, extract_ofdm_symbol_samples))
.def_static("calculate_channel",
&misc_utils::calculate_channel,
py::arg("symbol"),
py::arg("sample_rate"),
py::arg("symbol_idx"),
D(misc_utils, calculate_channel))
.def_static("qpsk_to_bits",
&misc_utils::qpsk_to_bits,
py::arg("samples"),
D(misc_utils, qpsk_to_bits))
.def_static("angle", &misc_utils::angle, py::arg("samples"), D(misc_utils, angle))
.def_static("abs_squared",
&misc_utils::abs_squared,
py::arg("samples"),
D(misc_utils, abs_squared))
;
}

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