kopia lustrzana https://github.com/proto17/dji_droneid
Working on porting to 3.10
rodzic
3bc45fe703
commit
ce69f6fc3c
|
@ -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
|
|
@ -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).
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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"
|
|
@ -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.
|
|
@ -1,3 +0,0 @@
|
|||
.idea/
|
||||
build/
|
||||
cmake-build-*/
|
|
@ -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}
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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.
|
||||
|
|
Plik diff jest za duży
Load Diff
|
@ -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()
|
||||
|
||||
|
|
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
|
@ -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
|
||||
|
||||
|
||||
|
|
Plik diff jest za duży
Load Diff
|
@ -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
|
||||
|
||||
|
|
|
@ -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('&', '&')
|
||||
s1 = s1.replace('<', '<')
|
||||
s1 = s1.replace('>', '>')
|
||||
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('&', '&')
|
||||
s1 = s1.replace('<', '<')
|
||||
|
@ -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()')
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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()
|
|
@ -4,4 +4,3 @@
|
|||
* module are listed here or in the subcategories below.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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)
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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.
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
)
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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
|
||||
)
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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)
|
|
@ -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
|
||||
#
|
|
@ -0,0 +1,5 @@
|
|||
*~
|
||||
*.pyc
|
||||
*.pyo
|
||||
build*/
|
||||
examples/grc/*.py
|
|
@ -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/
|
||||
)
|
|
@ -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
|
||||
#
|
|
@ -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)
|
|
@ -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)
|
|
@ -0,0 +1 @@
|
|||
This directory stores templates for docstrings that are scraped from the include header files for each block
|
|
@ -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";
|
|
@ -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())
|
|
@ -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
Ładowanie…
Reference in New Issue